diff --git a/README.md b/README.md index 24aa8b38a3..d663cfc3d2 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,15 @@ TUnit is designed to aid with all testing types: [![nuget](https://img.shields.io/nuget/v/TUnit.svg)](https://www.nuget.org/packages/TUnit/) [![NuGet Downloads](https://img.shields.io/nuget/dt/TUnit)](https://www.nuget.org/packages/TUnit/) ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/thomhurst/TUnit/dotnet.yml) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/thomhurst/TUnit/main) ![License](https://img.shields.io/github/license/thomhurst/TUnit) +## Quick Start + +Assuming you have the .NET SDK installed, simply run: + +`dotnet new install TUnit.Templates` +`dotnet new TUnit -n "YourProjectName"` + +A new test project will be created for you with some samples of different test types and tips. When you're ready to get going, delete them and create your own! + ## Documentation See here: diff --git a/README_Template.md b/README_Template.md index 96b9085d54..5be14f1559 100644 --- a/README_Template.md +++ b/README_Template.md @@ -16,6 +16,15 @@ TUnit is designed to aid with all testing types: [![nuget](https://img.shields.io/nuget/v/TUnit.svg)](https://www.nuget.org/packages/TUnit/) [![NuGet Downloads](https://img.shields.io/nuget/dt/TUnit)](https://www.nuget.org/packages/TUnit/) ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/thomhurst/TUnit/dotnet.yml) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/thomhurst/TUnit/main) ![License](https://img.shields.io/github/license/thomhurst/TUnit) +## Quick Start + +Assuming you have the .NET SDK installed, simply run: + +`dotnet new install TUnit.Templates` +`dotnet new TUnit -n "YourProjectName"` + +A new test project will be created for you with some samples of different test types and tips. When you're ready to get going, delete them and create your own! + ## Documentation See here: diff --git a/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs b/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs index 22ebd6c9ca..08ec190586 100644 --- a/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs +++ b/TUnit.Pipeline/Modules/GetPackageProjectsModule.cs @@ -1,6 +1,4 @@ using ModularPipelines.Context; -using ModularPipelines.Extensions; -using ModularPipelines.Git.Extensions; using ModularPipelines.Modules; using File = ModularPipelines.FileSystem.File; @@ -8,18 +6,18 @@ namespace TUnit.Pipeline.Modules; public class GetPackageProjectsModule : Module> { - protected override Task?> ExecuteAsync(IPipelineContext context, CancellationToken cancellationToken) + protected override async Task?> ExecuteAsync(IPipelineContext context, CancellationToken cancellationToken) { - return context.Git().RootDirectory - .GetFiles(x => x.Extension == ".csproj") - .Where(x => !x.Name.Contains("Pipeline", StringComparison.OrdinalIgnoreCase)) - .Where(x => !x.Name.Contains("Analyzer", StringComparison.OrdinalIgnoreCase)) - .Where(x => !x.Name.Contains("Generator", StringComparison.OrdinalIgnoreCase)) - .Where(x => !x.Name.Contains("Sample", StringComparison.OrdinalIgnoreCase)) - .Where(x => !x.Name.Contains("Test", StringComparison.OrdinalIgnoreCase)) - .Where(x => !x.Name.Contains("Timer", StringComparison.OrdinalIgnoreCase)) - .Where(x => !x.Name.Contains("CodeFix", StringComparison.OrdinalIgnoreCase)) - .ToList() - .AsTask?>(); + await Task.CompletedTask; + + return + [ + Sourcy.DotNet.Projects.TUnit_Assertions, + Sourcy.DotNet.Projects.TUnit_Core, + Sourcy.DotNet.Projects.TUnit_Engine, + Sourcy.DotNet.Projects.TUnit, + Sourcy.DotNet.Projects.TUnit_Playwright, + Sourcy.DotNet.Projects.TUnit_Templates + ]; } } \ No newline at end of file diff --git a/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs b/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs index c61ad091a7..b67c9589cb 100644 --- a/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs +++ b/TUnit.Pipeline/Modules/PackTUnitFilesModule.cs @@ -37,7 +37,7 @@ await context.DotNet() new KeyValue("AssemblyFileVersion", version.SemVer!), new KeyValue("IsPackTarget", "true") ], - IncludeSource = true, + IncludeSource = project == Sourcy.DotNet.Projects.TUnit_Templates ? false : true, Configuration = Configuration.Release, }, cancellationToken); diff --git a/TUnit.Pipeline/TUnit.Pipeline.csproj b/TUnit.Pipeline/TUnit.Pipeline.csproj index b8cc35811c..7a2e8af8f5 100644 --- a/TUnit.Pipeline/TUnit.Pipeline.csproj +++ b/TUnit.Pipeline/TUnit.Pipeline.csproj @@ -4,6 +4,12 @@ false false + + + + <_Parameter1>$(MSBuildProjectFullPath) + + Exe diff --git a/TUnit.Templates/README.md b/TUnit.Templates/README.md new file mode 100644 index 0000000000..f28f7c600a --- /dev/null +++ b/TUnit.Templates/README.md @@ -0,0 +1,5 @@ +# TUnit.Templates + +Some templates to help you get started with TUnit! + +For more information, check out the repository at https://www.github.com/thomhurst/TUnit \ No newline at end of file diff --git a/TUnit.Templates/TUnit.Templates.csproj b/TUnit.Templates/TUnit.Templates.csproj new file mode 100644 index 0000000000..3665784a95 --- /dev/null +++ b/TUnit.Templates/TUnit.Templates.csproj @@ -0,0 +1,39 @@ + + + + TUnit.Templates + 1.0 + TUnit Templates + Tom Longhurst + Templates for getting started with TUnit + TUnit,test,testing,unit,integration,acceptance + https://www.github.com/thomhurst/TUnit + + Template + net8.0 + true + false + content + $(NoWarn);NU5128 + true + README.md + + + + false + + + + + + + + + + + + + + + + diff --git a/TUnit.Templates/content/Directory.Build.props b/TUnit.Templates/content/Directory.Build.props new file mode 100644 index 0000000000..91a726632a --- /dev/null +++ b/TUnit.Templates/content/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/TUnit.Templates/content/Directory.Build.targets b/TUnit.Templates/content/Directory.Build.targets new file mode 100644 index 0000000000..0c98d167d1 --- /dev/null +++ b/TUnit.Templates/content/Directory.Build.targets @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/TUnit.Templates/content/Directory.Packages.props b/TUnit.Templates/content/Directory.Packages.props new file mode 100644 index 0000000000..5f9708a97f --- /dev/null +++ b/TUnit.Templates/content/Directory.Packages.props @@ -0,0 +1,5 @@ + + + false + + diff --git a/TUnit.Templates/content/TUnit/.template.config/template.json b/TUnit.Templates/content/TUnit/.template.config/template.json new file mode 100644 index 0000000000..772e07bd94 --- /dev/null +++ b/TUnit.Templates/content/TUnit/.template.config/template.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json.schemastore.org/template", + "author": "Tom Longhurst", + "description": "Templates for getting started with TUnit", + "classifications": [ + "Test", + "TUnit" + ], + "name": "TUnit Test Project", + "identity": "TUnit.Test.Project", + "groupIdentity": "TUnit", + "shortName": "TUnit", + "tags": { + "language": "C#", + "type": "project" + }, + "sourceName": "TestProject", + "preferNameDirectory": true + } + \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit/Data/DataClass.cs b/TUnit.Templates/content/TUnit/Data/DataClass.cs new file mode 100644 index 0000000000..4a15d696b3 --- /dev/null +++ b/TUnit.Templates/content/TUnit/Data/DataClass.cs @@ -0,0 +1,16 @@ +using TUnit.Core.Interfaces; + +namespace TestProject; + +public class DataClass : IAsyncInitializer, IAsyncDisposable +{ + public Task InitializeAsync() + { + return Console.Out.WriteLineAsync("Classes can be injected into tests, and they can perform some initialisation logic such as starting an in-memory server or a test container."); + } + + public async ValueTask DisposeAsync() + { + await Console.Out.WriteLineAsync("And when the class is finished with, we can clean up any resources."); + } +} \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit/Data/DataGenerator.cs b/TUnit.Templates/content/TUnit/Data/DataGenerator.cs new file mode 100644 index 0000000000..9b409f7d17 --- /dev/null +++ b/TUnit.Templates/content/TUnit/Data/DataGenerator.cs @@ -0,0 +1,11 @@ +namespace TestProject.Data; + +public class DataGenerator : DataSourceGeneratorAttribute +{ + public override IEnumerable> GenerateDataSources(DataGeneratorMetadata dataGeneratorMetadata) + { + yield return () => (1, 1, 2); + yield return () => (1, 2, 3); + yield return () => (4, 5, 9); + } +} \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit/Data/DependencyInjectionClassConstructor.cs b/TUnit.Templates/content/TUnit/Data/DependencyInjectionClassConstructor.cs new file mode 100644 index 0000000000..82378bd8c0 --- /dev/null +++ b/TUnit.Templates/content/TUnit/Data/DependencyInjectionClassConstructor.cs @@ -0,0 +1,18 @@ +using TUnit.Core.Interfaces; + +namespace TestProject; + +public class DependencyInjectionClassConstructor : IClassConstructor +{ + public T Create(ClassConstructorMetadata classConstructorMetadata) where T : class + { + Console.WriteLine("You can also control how your test classes are new'd up, giving you lots of power and the ability to utilise tools such as dependency injection"); + + if (typeof(T) == typeof(AndEvenMoreTests)) + { + return (new AndEvenMoreTests(new DataClass()) as T)!; + } + + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit/GlobalSetup.cs b/TUnit.Templates/content/TUnit/GlobalSetup.cs new file mode 100644 index 0000000000..442534393d --- /dev/null +++ b/TUnit.Templates/content/TUnit/GlobalSetup.cs @@ -0,0 +1,21 @@ +// Here you could define global logic that would affect all tests + +// You can use attributes at the assembly level to apply to all tests in the assembly +[assembly: Retry(3)] + +namespace TestProject; + +public class GlobalHooks +{ + [Before(TestSession)] + public static void SetUp() + { + Console.WriteLine("Or you can define methods that do stuff before..."); + } + + [After(TestSession)] + public static void CleanUp() + { + Console.WriteLine("...and after!"); + } +} \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit/TestProject.csproj b/TUnit.Templates/content/TUnit/TestProject.csproj new file mode 100644 index 0000000000..29c022516f --- /dev/null +++ b/TUnit.Templates/content/TUnit/TestProject.csproj @@ -0,0 +1,14 @@ + + + + enable + enable + Exe + net8.0 + + + + + + + diff --git a/TUnit.Templates/content/TUnit/Tests.cs b/TUnit.Templates/content/TUnit/Tests.cs new file mode 100644 index 0000000000..5425b19b0a --- /dev/null +++ b/TUnit.Templates/content/TUnit/Tests.cs @@ -0,0 +1,65 @@ +using TestProject.Data; + +namespace TestProject; + +public class Tests +{ + [Test] + public void Basic() + { + Console.WriteLine("This is a basic test"); + } + + [Test] + [Arguments(1, 2, 3)] + [Arguments(2, 3, 5)] + public async Task DataDrivenArguments(int a, int b, int c) + { + Console.WriteLine("This one can accept arguments from an attribute"); + + var result = a + b; + + await Assert.That(result).IsEqualTo(c); + } + + [Test] + [MethodDataSource(nameof(DataSource))] + public async Task MethodDataSource(int a, int b, int c) + { + Console.WriteLine("This one can accept arguments from a method"); + + var result = a + b; + + await Assert.That(result).IsEqualTo(c); + } + + [Test] + [ClassDataSource] + [ClassDataSource(Shared = SharedType.PerClass)] + [ClassDataSource(Shared = SharedType.PerAssembly)] + [ClassDataSource(Shared = SharedType.PerTestSession)] + public void ClassDataSource(DataClass dataClass) + { + Console.WriteLine("This test can accept a class, which can also be pre-initialised before being injected in"); + + Console.WriteLine("These can also be shared among other tests, or new'd up each time, by using the `Shared` property on the attribute"); + } + + [Test] + [DataGenerator] + public async Task CustomDataGenerator(int a, int b, int c) + { + Console.WriteLine("You can even define your own custom data generators"); + + var result = a + b; + + await Assert.That(result).IsEqualTo(c); + } + + public static IEnumerable<(int a, int b, int c)> DataSource() + { + yield return (1, 1, 2); + yield return (2, 1, 3); + yield return (3, 1, 4); + } +} \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit/Tests2.cs b/TUnit.Templates/content/TUnit/Tests2.cs new file mode 100644 index 0000000000..c7aba7c85b --- /dev/null +++ b/TUnit.Templates/content/TUnit/Tests2.cs @@ -0,0 +1,28 @@ +namespace TestProject; + +[Arguments("Hello")] +[Arguments("World")] +public class MoreTests(string title) +{ + [Test] + public void ClassLevelDataRow() + { + Console.WriteLine(title); + Console.WriteLine("Did I forget that data injection works on classes too?"); + } + + // You can even inject in ClassDataSources as properties to avoid repetitive constructors if you're using inheritance! + [ClassDataSource(Shared = SharedType.PerTestSession)] + public required DataClass DataClass { get; init; } + + [Test] + public void Matrices( + [Matrix(1, 2, 3)] int a, + [Matrix(true, false)] bool b, + [Matrix("A", "B", "C")] string c) + { + Console.WriteLine("A new test will be created for each data row, whether it's on the class or method level!"); + + Console.WriteLine("Oh and this is a matrix test. That means all combinations of inputs are attempted."); + } +} \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit/Tests3.cs b/TUnit.Templates/content/TUnit/Tests3.cs new file mode 100644 index 0000000000..be621ab1f6 --- /dev/null +++ b/TUnit.Templates/content/TUnit/Tests3.cs @@ -0,0 +1,14 @@ +namespace TestProject; + +[ClassDataSource] +[ClassConstructor] +public class AndEvenMoreTests(DataClass dataClass) +{ + [Test] + public void HaveFun() + { + Console.WriteLine(dataClass); + Console.WriteLine("For more information, check out the documentation"); + Console.WriteLine("https://thomhurst.github.io/TUnit/"); + } +} \ No newline at end of file diff --git a/TUnit.sln b/TUnit.sln index ce4b089df7..bd95cdede5 100644 --- a/TUnit.sln +++ b/TUnit.sln @@ -69,6 +69,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUnit.Analyzers.Roslyn47", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TUnit.Engine.Tests", "TUnit.Engine.Tests\TUnit.Engine.Tests.csproj", "{E0E07E64-BC0A-489E-B562-2982F3836994}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "TUnit.Templates\content\TUnit\TestProject.csproj", "{4BFDDFDB-96D9-42AA-85CE-9FBD017ACBE1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -183,6 +185,10 @@ Global {E0E07E64-BC0A-489E-B562-2982F3836994}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0E07E64-BC0A-489E-B562-2982F3836994}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0E07E64-BC0A-489E-B562-2982F3836994}.Release|Any CPU.Build.0 = Release|Any CPU + {4BFDDFDB-96D9-42AA-85CE-9FBD017ACBE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4BFDDFDB-96D9-42AA-85CE-9FBD017ACBE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4BFDDFDB-96D9-42AA-85CE-9FBD017ACBE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4BFDDFDB-96D9-42AA-85CE-9FBD017ACBE1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -211,6 +217,7 @@ Global {744CD312-B913-48E0-B917-531ED2A9A541} = {503DA9FA-045D-4910-8AF6-905E6048B1F1} {54D5F1A7-7979-4C07-8FE1-426233846018} = {503DA9FA-045D-4910-8AF6-905E6048B1F1} {E0E07E64-BC0A-489E-B562-2982F3836994} = {62AD1EAF-43C4-4AC0-B9FA-CD59739B3850} + {4BFDDFDB-96D9-42AA-85CE-9FBD017ACBE1} = {0BA988BF-ADCE-4343-9098-B4EF65C43709} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {109D285A-36B3-4503-BCDF-8E26FB0E2C5B} diff --git a/docs/docs/tutorial-basics/installing.md b/docs/docs/tutorial-basics/installing.md index 73b74f2ebf..ef05889af2 100644 --- a/docs/docs/tutorial-basics/installing.md +++ b/docs/docs/tutorial-basics/installing.md @@ -4,6 +4,17 @@ sidebar_position: 1 # Installing TUnit +## Easily + +Assuming you have the .NET SDK installed, simply run: + +`dotnet new install TUnit.Templates` +`dotnet new TUnit -n "YourProjectName"` + +A new test project will be created for you with some samples of different test types and tips. When you're ready to get going, delete them and create your own! + +## Manually + First create an empty .NET console application: ```powershell