diff --git a/TUnit.Templates.Tests/AspNetTemplateTests.cs b/TUnit.Templates.Tests/AspNetTemplateTests.cs index dfbb461652..6b4a46b884 100644 --- a/TUnit.Templates.Tests/AspNetTemplateTests.cs +++ b/TUnit.Templates.Tests/AspNetTemplateTests.cs @@ -2,7 +2,7 @@ public class AspNetTemplateTests : TemplateTestBase { - protected override string TemplateShortName => "TUnit.AspNet"; + protected override string TemplateShortName { get; set; } = "TUnit.AspNet"; [Test] public async Task InstantiationTest() diff --git a/TUnit.Templates.Tests/AspireStarterTemplateTests.cs b/TUnit.Templates.Tests/AspireStarterTemplateTests.cs index d38bfef603..25f8dd0c2f 100644 --- a/TUnit.Templates.Tests/AspireStarterTemplateTests.cs +++ b/TUnit.Templates.Tests/AspireStarterTemplateTests.cs @@ -2,7 +2,7 @@ { public class AspireStarterTemplateTests : TemplateTestBase { - protected override string TemplateShortName => "TUnit.Aspire.Starter"; + protected override string TemplateShortName { get; set; } = "TUnit.Aspire.Starter"; [Test] public async Task InstantiationTest() diff --git a/TUnit.Templates.Tests/AspireTemplateTests.cs b/TUnit.Templates.Tests/AspireTemplateTests.cs index 2f76417ce1..6d7b8e0b53 100644 --- a/TUnit.Templates.Tests/AspireTemplateTests.cs +++ b/TUnit.Templates.Tests/AspireTemplateTests.cs @@ -2,7 +2,7 @@ { public class AspireTemplateTests:TemplateTestBase { - protected override string TemplateShortName => "TUnit.Aspire.Test"; + protected override string TemplateShortName { get; set; } = "TUnit.Aspire.Test"; [Test] public async Task InstantiationTest() diff --git a/TUnit.Templates.Tests/BasicTemplateTests.cs b/TUnit.Templates.Tests/BasicTemplateTests.cs index 355d5ac019..3eb5deea5e 100644 --- a/TUnit.Templates.Tests/BasicTemplateTests.cs +++ b/TUnit.Templates.Tests/BasicTemplateTests.cs @@ -2,11 +2,25 @@ public class BasicTemplateTests : TemplateTestBase { - protected override string TemplateShortName => "TUnit"; + protected override string TemplateShortName { get; set; } = "TUnit"; [Test] public async Task InstantiationTest() { await Engine.Execute(Options).ConfigureAwait(false); } + + [Test] + public async Task InstantiationTestWithFSharp() + { + TemplateShortName = "TUnit.FSharp"; + await Engine.Execute(Options).ConfigureAwait(false); + } + + [Test] + public async Task InstantiationTestWithVB() + { + TemplateShortName = "TUnit.VB"; + await Engine.Execute(Options).ConfigureAwait(false); + } } \ No newline at end of file diff --git a/TUnit.Templates.Tests/PlaywriteTemplateTests.cs b/TUnit.Templates.Tests/PlaywriteTemplateTests.cs index 701154266a..ff3516a6ec 100644 --- a/TUnit.Templates.Tests/PlaywriteTemplateTests.cs +++ b/TUnit.Templates.Tests/PlaywriteTemplateTests.cs @@ -2,7 +2,7 @@ public class PlaywriteTemplateTests : TemplateTestBase { - protected override string TemplateShortName => "TUnit.Playwright"; + protected override string TemplateShortName { get; set; } = "TUnit.Playwright"; [Test] public async Task InstantiationTest() diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DataClass.fs b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DataClass.fs new file mode 100644 index 0000000000..7eba8bdce3 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DataClass.fs @@ -0,0 +1,15 @@ +namespace TUnit.FSharp + +open System +open System.Threading.Tasks +open TUnit.Core.Interfaces + +type DataClass() = + interface IAsyncInitializer with + member _.InitializeAsync() : Task = + 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.") + + interface IAsyncDisposable with + member _.DisposeAsync() : ValueTask = + ValueTask(Console.Out.WriteLineAsync("And when the class is finished with, we can clean up any resources.")) + diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DataGenerator.fs b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DataGenerator.fs new file mode 100644 index 0000000000..38605fb295 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DataGenerator.fs @@ -0,0 +1,16 @@ +namespace TUnit.FSharp.Data + +open System +open System.Collections.Generic +open TUnit.Core + +type DataGenerator() = + inherit DataSourceGeneratorAttribute() + + override _.GenerateDataSources(_: DataGeneratorMetadata) : IEnumerable> = + seq { + yield Func(fun () -> struct (1, 1, 2)) + yield Func(fun () -> struct (1, 2, 3)) + yield Func(fun () -> struct (4, 5, 9)) + } + diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DependencyInjectionClassConstructor.fs b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DependencyInjectionClassConstructor.fs new file mode 100644 index 0000000000..7234fc5724 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Data/DependencyInjectionClassConstructor.fs @@ -0,0 +1,18 @@ +namespace TUnit.FSharp + +open System +open Microsoft.Extensions.DependencyInjection +open TUnit.Core.Interfaces +open TUnit.Core + +type DependencyInjectionClassConstructor() = + let serviceProvider = + ServiceCollection() + // Register your dependencies here, e.g.: + .AddTransient() + .BuildServiceProvider() + + interface IClassConstructor with + member _.Create(typ: Type, _: ClassConstructorMetadata) : obj = + 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") + ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typ) \ No newline at end of file diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/GlobalSetup.fs b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/GlobalSetup.fs new file mode 100644 index 0000000000..8300f84d5a --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/GlobalSetup.fs @@ -0,0 +1,22 @@ +namespace TUnit.FSharp + +// 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 +open System +open System.Diagnostics.CodeAnalysis +open TUnit.Core + +[] +[] +do () + +type GlobalHooks() = + [] + static member SetUp() = + Console.WriteLine("Or you can define methods that do stuff before...") + + [] + static member CleanUp() = + Console.WriteLine("...and after!") + diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/TUnit.FSharp.fsproj b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/TUnit.FSharp.fsproj new file mode 100644 index 0000000000..0988e44e09 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/TUnit.FSharp.fsproj @@ -0,0 +1,27 @@ + + + + latest + enable + enable + Exe + net8.0 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests.fs b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests.fs new file mode 100644 index 0000000000..67a19d22ad --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests.fs @@ -0,0 +1,62 @@ +namespace TUnit.FSharp + +open System +open System.Collections.Generic +open System.Threading.Tasks +open TUnit.FSharp.Data +open TUnit +open TUnit.Core +open TUnit.Assertions +open TUnit.Assertions.Extensions +open TUnit.Assertions.FSharp.Operations + +type Tests() = + + [] + member _.Basic() = + Console.WriteLine("This is a basic test") + + [] + [] + [] + member _.DataDrivenArguments(a: int, b: int, c: int) = + async { + Console.WriteLine("This one can accept arguments from an attribute") + let result = a + b + do! check(Assert.That(result).IsEqualTo(c)) + } + + + [] + [] + member _.MethodDataSource(a: int, b: int, c: int) = + async { + Console.WriteLine("This one can accept arguments from a method") + let result = a + b + do! check(Assert.That(result).IsEqualTo(c)) + } + + [] + [)>] + [, Shared = SharedType.PerClass)>] + [, Shared = SharedType.PerAssembly)>] + [, Shared = SharedType.PerTestSession)>] + member _.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") + + [] + [] + member _.CustomDataGenerator(a: int, b: int, c: int) = + async { + Console.WriteLine("You can even define your own custom data generators") + let result = a + b + do! check(Assert.That(result).IsEqualTo(c)) + } + + static member DataSource() : IEnumerable = + seq { + yield struct (1, 1, 2) + yield struct (2, 1, 3) + yield struct (3, 1, 4) + } diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests2.fs b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests2.fs new file mode 100644 index 0000000000..73fc85bf88 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests2.fs @@ -0,0 +1,27 @@ +namespace TUnit.FSharp + +open System +open TUnit.Core + +[] +[] +type MoreTests(title: string) = + + [] + member _.ClassLevelDataRow() = + Console.WriteLine(title) + Console.WriteLine("Did I forget that data injection works on classes too?") + + [, Shared = SharedType.PerTestSession)>] + member val DataClass: DataClass = Unchecked.defaultof<_> with get, set + + [] + [] + member _.Matrices + ( + [] a: int, + [] b: bool, + [] c: string + ) = + 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.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests3.fs b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests3.fs new file mode 100644 index 0000000000..3d446f1d4f --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithFSharp.TUnit.FSharp._.verified/TUnit.FSharp/Tests3.fs @@ -0,0 +1,15 @@ +namespace TUnit.FSharp + +open System +open TUnit.Core + +[)>] +[)>] +type AndEvenMoreTests(dataClass: DataClass) = + + [] + member _.HaveFun() = + Console.WriteLine(dataClass) + Console.WriteLine("For more information, check out the documentation") + Console.WriteLine("https://tunit.dev/") + diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DataClass.vb b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DataClass.vb new file mode 100644 index 0000000000..90fdd414db --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DataClass.vb @@ -0,0 +1,19 @@ +Imports System +Imports System.Threading.Tasks +Imports TUnit.Core.Interfaces + +Public Class DataClass + Implements IAsyncInitializer, IAsyncDisposable + + Public Function InitializeAsync() As Task Implements IAsyncInitializer.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.") + End Function + + Public Function DisposeAsync() As ValueTask Implements IAsyncDisposable.DisposeAsync + Return New ValueTask(DisposeAsyncTask()) + End Function + + Private Async Function DisposeAsyncTask() As Task + Await Console.Out.WriteLineAsync("And when the class is finished with, we can clean up any resources.") + End Function +End Class diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DataGenerator.vb b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DataGenerator.vb new file mode 100644 index 0000000000..894171ee1d --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DataGenerator.vb @@ -0,0 +1,17 @@ +Imports System +Imports System.Collections.Generic +Imports TUnit.Core + +Namespace Data + Public Class DataGenerator + Inherits DataSourceGeneratorAttribute(Of Integer, Integer, Integer) + + Public Overrides Iterator Function GenerateDataSources(dataGeneratorMetadata As DataGeneratorMetadata) As IEnumerable(Of Func(Of (Integer, Integer, Integer))) + Yield Function() (1, 1, 2) + Yield Function() (1, 2, 3) + Yield Function() (4, 5, 9) + End Function + + End Class +End Namespace + diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DependencyInjectionClassConstructor.vb b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DependencyInjectionClassConstructor.vb new file mode 100644 index 0000000000..1a19ea7436 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Data/DependencyInjectionClassConstructor.vb @@ -0,0 +1,26 @@ +Imports System +Imports TUnit.Core +Imports TUnit.Core.Interfaces +Public Class DependencyInjectionClassConstructor + Implements IClassConstructor + + Public Function Create(Of T As Class)(classConstructorMetadata As ClassConstructorMetadata) As T + 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 GetType(T) Is GetType(AndEvenMoreTests) Then + Return CType(DirectCast(New AndEvenMoreTests(New DataClass()), Object), T) + End If + + Throw New NotImplementedException() + End Function + + ' Explicit interface implementation for IClassConstructor.Create(Type, ClassConstructorMetadata) + Private Function IClassConstructor_Create(type As Type, classConstructorMetadata As ClassConstructorMetadata) As Object Implements IClassConstructor.Create + If type Is GetType(AndEvenMoreTests) Then + Return New AndEvenMoreTests(New DataClass()) + End If + + Throw New NotImplementedException() + End Function + +End Class \ No newline at end of file diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/GlobalSetup.vb b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/GlobalSetup.vb new file mode 100644 index 0000000000..9551a1e9c3 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/GlobalSetup.vb @@ -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 +Imports TUnit.Core + + + + +Public Class GlobalHooks + + + Public Shared Sub SetUp() + Console.WriteLine("Or you can define methods that do stuff before...") + End Sub + + + Public Shared Sub CleanUp() + Console.WriteLine("...and after!") + End Sub + +End Class \ No newline at end of file diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/TUnit.VB.vbproj b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/TUnit.VB.vbproj new file mode 100644 index 0000000000..ada701afeb --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/TUnit.VB.vbproj @@ -0,0 +1,13 @@ + + + + net8.0 + latest + enable + enable + + + + + + diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests.vb b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests.vb new file mode 100644 index 0000000000..61100db1bc --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests.vb @@ -0,0 +1,65 @@ +Imports System +Imports System.Collections.Generic +Imports System.Threading.Tasks +Imports TUnit.VB.Data +Imports TUnit.Assertions +Imports TUnit.Assertions.Extensions +Imports TUnit.Core + + +Namespace TUnit.VB + + Public Class Tests + + + Public Sub Basic() + Console.WriteLine("This is a basic test") + End Sub + + + + + Public Async Function DataDrivenArguments(a As Integer, b As Integer, c As Integer) As Task + Console.WriteLine("This one can accept arguments from an attribute") + + Dim result = a + b + + Await Assert.That(result).IsEqualTo(c) + End Function + + + + Public Async Function MethodDataSource(a As Integer, b As Integer, c As Integer) As Task + Console.WriteLine("This one can accept arguments from a method") + + Dim result = a + b + + Await Assert.That(result).IsEqualTo(c) + End Function + + + + Public Sub ClassDataSourceTest(dataClass As DataClass) + Console.WriteLine("This test can accept a class, which can also be pre-initialized 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") + End Sub + + + + Public Async Function CustomDataGenerator(a As Integer, b As Integer, c As Integer) As Task + Console.WriteLine("You can even define your own custom data generators") + + Dim result = a + b + + Await Assert.That(result).IsEqualTo(c) + End Function + + Public Shared Iterator Function DataSource() As IEnumerable(Of (a As Integer, b As Integer, c As Integer)) + Yield (1, 1, 2) + Yield (2, 1, 3) + Yield (3, 1, 4) + End Function + + End Class + +End Namespace \ No newline at end of file diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests2.vb b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests2.vb new file mode 100644 index 0000000000..2244bd7ef8 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests2.vb @@ -0,0 +1,32 @@ +Imports System +Imports TUnit.Core + + + +Public Class MoreTests + Private ReadOnly _title As String + + Public Sub New(title As String) + _title = title + End Sub + + + Public Sub ClassLevelDataRow() + Console.WriteLine(_title) + Console.WriteLine("Did I forget that data injection works on classes too?") + End Sub + + + Public Property DataClass As DataClass + + + + Public Sub Matrices( + a As Integer, + b As Boolean, + c As String) + 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.") + End Sub + +End Class \ No newline at end of file diff --git a/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests3.vb b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests3.vb new file mode 100644 index 0000000000..4cadd2f0b9 --- /dev/null +++ b/TUnit.Templates.Tests/Snapshots/InstantiationTestWithVB.TUnit.VB._.verified/TUnit.VB/Tests3.vb @@ -0,0 +1,20 @@ +Imports System +Imports TUnit.Core + + + +Public Class AndEvenMoreTests + + Private ReadOnly _dataClass As DataClass + + Public Sub New(dataClass As DataClass) + _dataClass = dataClass + End Sub + + + Public Sub HaveFun() + Console.WriteLine(_dataClass) + Console.WriteLine("For more information, check out the documentation") + Console.WriteLine("https://tunit.dev/") + End Sub +End Class \ No newline at end of file diff --git a/TUnit.Templates.Tests/TemplateTestBase.cs b/TUnit.Templates.Tests/TemplateTestBase.cs index 5c762d5d3b..4d32c92369 100644 --- a/TUnit.Templates.Tests/TemplateTestBase.cs +++ b/TUnit.Templates.Tests/TemplateTestBase.cs @@ -18,7 +18,7 @@ public abstract partial class TemplateTestBase : IDisposable private bool _disposed; private readonly ILoggerFactory _loggerFactory = LoggerFactory.Create(builder => builder.AddConsole()); - protected abstract string TemplateShortName { get; } + protected abstract string TemplateShortName { get; set; } protected VerificationEngine Engine => new(_loggerFactory); diff --git a/TUnit.Templates/content/TUnit.FSharp/.template.config/template.json b/TUnit.Templates/content/TUnit.FSharp/.template.config/template.json new file mode 100644 index 0000000000..d6e181ebd0 --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/.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 Mixed Test Project", + "identity": "TUnit.Test.Mixed.FSharp", + "groupIdentity": "TUnit", + "shortName": "TUnit.FSharp", + "tags": { + "language": "F#", + "type": "project" + }, + "sourceName": "TestProject", + "preferNameDirectory": true + } + \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.FSharp/Data/DataClass.fs b/TUnit.Templates/content/TUnit.FSharp/Data/DataClass.fs new file mode 100644 index 0000000000..86ca023aa9 --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/Data/DataClass.fs @@ -0,0 +1,15 @@ +namespace TestProject + +open System +open System.Threading.Tasks +open TUnit.Core.Interfaces + +type DataClass() = + interface IAsyncInitializer with + member _.InitializeAsync() : Task = + 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.") + + interface IAsyncDisposable with + member _.DisposeAsync() : ValueTask = + ValueTask(Console.Out.WriteLineAsync("And when the class is finished with, we can clean up any resources.")) + diff --git a/TUnit.Templates/content/TUnit.FSharp/Data/DataGenerator.fs b/TUnit.Templates/content/TUnit.FSharp/Data/DataGenerator.fs new file mode 100644 index 0000000000..c67e016478 --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/Data/DataGenerator.fs @@ -0,0 +1,16 @@ +namespace TestProject.Data + +open System +open System.Collections.Generic +open TUnit.Core + +type DataGenerator() = + inherit DataSourceGeneratorAttribute() + + override _.GenerateDataSources(_: DataGeneratorMetadata) : IEnumerable> = + seq { + yield Func(fun () -> struct (1, 1, 2)) + yield Func(fun () -> struct (1, 2, 3)) + yield Func(fun () -> struct (4, 5, 9)) + } + diff --git a/TUnit.Templates/content/TUnit.FSharp/Data/DependencyInjectionClassConstructor.fs b/TUnit.Templates/content/TUnit.FSharp/Data/DependencyInjectionClassConstructor.fs new file mode 100644 index 0000000000..253222f14d --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/Data/DependencyInjectionClassConstructor.fs @@ -0,0 +1,18 @@ +namespace TestProject + +open System +open Microsoft.Extensions.DependencyInjection +open TUnit.Core.Interfaces +open TUnit.Core + +type DependencyInjectionClassConstructor() = + let serviceProvider = + ServiceCollection() + // Register your dependencies here, e.g.: + .AddTransient() + .BuildServiceProvider() + + interface IClassConstructor with + member _.Create(typ: Type, _: ClassConstructorMetadata) : obj = + 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") + ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, typ) \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.FSharp/GlobalSetup.fs b/TUnit.Templates/content/TUnit.FSharp/GlobalSetup.fs new file mode 100644 index 0000000000..e8e1a6dc17 --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/GlobalSetup.fs @@ -0,0 +1,22 @@ +namespace TestProject + +// 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 +open System +open System.Diagnostics.CodeAnalysis +open TUnit.Core + +[] +[] +do () + +type GlobalHooks() = + [] + static member SetUp() = + Console.WriteLine("Or you can define methods that do stuff before...") + + [] + static member CleanUp() = + Console.WriteLine("...and after!") + diff --git a/TUnit.Templates/content/TUnit.FSharp/TestProject.fsproj b/TUnit.Templates/content/TUnit.FSharp/TestProject.fsproj new file mode 100644 index 0000000000..0988e44e09 --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/TestProject.fsproj @@ -0,0 +1,27 @@ + + + + latest + enable + enable + Exe + net8.0 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.FSharp/Tests.fs b/TUnit.Templates/content/TUnit.FSharp/Tests.fs new file mode 100644 index 0000000000..82d2e7faae --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/Tests.fs @@ -0,0 +1,62 @@ +namespace TestProject + +open System +open System.Collections.Generic +open System.Threading.Tasks +open TestProject.Data +open TUnit +open TUnit.Core +open TUnit.Assertions +open TUnit.Assertions.Extensions +open TUnit.Assertions.FSharp.Operations + +type Tests() = + + [] + member _.Basic() = + Console.WriteLine("This is a basic test") + + [] + [] + [] + member _.DataDrivenArguments(a: int, b: int, c: int) = + async { + Console.WriteLine("This one can accept arguments from an attribute") + let result = a + b + do! check(Assert.That(result).IsEqualTo(c)) + } + + + [] + [] + member _.MethodDataSource(a: int, b: int, c: int) = + async { + Console.WriteLine("This one can accept arguments from a method") + let result = a + b + do! check(Assert.That(result).IsEqualTo(c)) + } + + [] + [)>] + [, Shared = SharedType.PerClass)>] + [, Shared = SharedType.PerAssembly)>] + [, Shared = SharedType.PerTestSession)>] + member _.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") + + [] + [] + member _.CustomDataGenerator(a: int, b: int, c: int) = + async { + Console.WriteLine("You can even define your own custom data generators") + let result = a + b + do! check(Assert.That(result).IsEqualTo(c)) + } + + static member DataSource() : IEnumerable = + seq { + yield struct (1, 1, 2) + yield struct (2, 1, 3) + yield struct (3, 1, 4) + } diff --git a/TUnit.Templates/content/TUnit.FSharp/Tests2.fs b/TUnit.Templates/content/TUnit.FSharp/Tests2.fs new file mode 100644 index 0000000000..b95d32965e --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/Tests2.fs @@ -0,0 +1,27 @@ +namespace TestProject + +open System +open TUnit.Core + +[] +[] +type MoreTests(title: string) = + + [] + member _.ClassLevelDataRow() = + Console.WriteLine(title) + Console.WriteLine("Did I forget that data injection works on classes too?") + + [, Shared = SharedType.PerTestSession)>] + member val DataClass: DataClass = Unchecked.defaultof<_> with get, set + + [] + [] + member _.Matrices + ( + [] a: int, + [] b: bool, + [] c: string + ) = + 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.FSharp/Tests3.fs b/TUnit.Templates/content/TUnit.FSharp/Tests3.fs new file mode 100644 index 0000000000..45fff9da48 --- /dev/null +++ b/TUnit.Templates/content/TUnit.FSharp/Tests3.fs @@ -0,0 +1,15 @@ +namespace TestProject + +open System +open TUnit.Core + +[)>] +[)>] +type AndEvenMoreTests(dataClass: DataClass) = + + [] + member _.HaveFun() = + Console.WriteLine(dataClass) + Console.WriteLine("For more information, check out the documentation") + Console.WriteLine("https://tunit.dev/") + diff --git a/TUnit.Templates/content/TUnit.VB/.template.config/template.json b/TUnit.Templates/content/TUnit.VB/.template.config/template.json new file mode 100644 index 0000000000..96e36faef0 --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/.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 Mixed Test Project", + "identity": "TUnit.Test.Mixed.VB", + "groupIdentity": "TUnit", + "shortName": "TUnit.VB", + "tags": { + "language": "VB", + "type": "project" + }, + "sourceName": "TestProject", + "preferNameDirectory": true + } + \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.VB/Data/DataClass.vb b/TUnit.Templates/content/TUnit.VB/Data/DataClass.vb new file mode 100644 index 0000000000..90fdd414db --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/Data/DataClass.vb @@ -0,0 +1,19 @@ +Imports System +Imports System.Threading.Tasks +Imports TUnit.Core.Interfaces + +Public Class DataClass + Implements IAsyncInitializer, IAsyncDisposable + + Public Function InitializeAsync() As Task Implements IAsyncInitializer.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.") + End Function + + Public Function DisposeAsync() As ValueTask Implements IAsyncDisposable.DisposeAsync + Return New ValueTask(DisposeAsyncTask()) + End Function + + Private Async Function DisposeAsyncTask() As Task + Await Console.Out.WriteLineAsync("And when the class is finished with, we can clean up any resources.") + End Function +End Class diff --git a/TUnit.Templates/content/TUnit.VB/Data/DataGenerator.vb b/TUnit.Templates/content/TUnit.VB/Data/DataGenerator.vb new file mode 100644 index 0000000000..894171ee1d --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/Data/DataGenerator.vb @@ -0,0 +1,17 @@ +Imports System +Imports System.Collections.Generic +Imports TUnit.Core + +Namespace Data + Public Class DataGenerator + Inherits DataSourceGeneratorAttribute(Of Integer, Integer, Integer) + + Public Overrides Iterator Function GenerateDataSources(dataGeneratorMetadata As DataGeneratorMetadata) As IEnumerable(Of Func(Of (Integer, Integer, Integer))) + Yield Function() (1, 1, 2) + Yield Function() (1, 2, 3) + Yield Function() (4, 5, 9) + End Function + + End Class +End Namespace + diff --git a/TUnit.Templates/content/TUnit.VB/Data/DependencyInjectionClassConstructor.vb b/TUnit.Templates/content/TUnit.VB/Data/DependencyInjectionClassConstructor.vb new file mode 100644 index 0000000000..1a19ea7436 --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/Data/DependencyInjectionClassConstructor.vb @@ -0,0 +1,26 @@ +Imports System +Imports TUnit.Core +Imports TUnit.Core.Interfaces +Public Class DependencyInjectionClassConstructor + Implements IClassConstructor + + Public Function Create(Of T As Class)(classConstructorMetadata As ClassConstructorMetadata) As T + 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 GetType(T) Is GetType(AndEvenMoreTests) Then + Return CType(DirectCast(New AndEvenMoreTests(New DataClass()), Object), T) + End If + + Throw New NotImplementedException() + End Function + + ' Explicit interface implementation for IClassConstructor.Create(Type, ClassConstructorMetadata) + Private Function IClassConstructor_Create(type As Type, classConstructorMetadata As ClassConstructorMetadata) As Object Implements IClassConstructor.Create + If type Is GetType(AndEvenMoreTests) Then + Return New AndEvenMoreTests(New DataClass()) + End If + + Throw New NotImplementedException() + End Function + +End Class \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.VB/GlobalSetup.vb b/TUnit.Templates/content/TUnit.VB/GlobalSetup.vb new file mode 100644 index 0000000000..9551a1e9c3 --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/GlobalSetup.vb @@ -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 +Imports TUnit.Core + + + + +Public Class GlobalHooks + + + Public Shared Sub SetUp() + Console.WriteLine("Or you can define methods that do stuff before...") + End Sub + + + Public Shared Sub CleanUp() + Console.WriteLine("...and after!") + End Sub + +End Class \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.VB/TestProject.vbproj b/TUnit.Templates/content/TUnit.VB/TestProject.vbproj new file mode 100644 index 0000000000..2c8a5b1b2a --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/TestProject.vbproj @@ -0,0 +1,13 @@ + + + + net8.0 + latest + enable + enable + + + + + + diff --git a/TUnit.Templates/content/TUnit.VB/Tests.vb b/TUnit.Templates/content/TUnit.VB/Tests.vb new file mode 100644 index 0000000000..1892050721 --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/Tests.vb @@ -0,0 +1,65 @@ +Imports System +Imports System.Collections.Generic +Imports System.Threading.Tasks +Imports TestProject.Data +Imports TUnit.Assertions +Imports TUnit.Assertions.Extensions +Imports TUnit.Core + + +Namespace TestProject + + Public Class Tests + + + Public Sub Basic() + Console.WriteLine("This is a basic test") + End Sub + + + + + Public Async Function DataDrivenArguments(a As Integer, b As Integer, c As Integer) As Task + Console.WriteLine("This one can accept arguments from an attribute") + + Dim result = a + b + + Await Assert.That(result).IsEqualTo(c) + End Function + + + + Public Async Function MethodDataSource(a As Integer, b As Integer, c As Integer) As Task + Console.WriteLine("This one can accept arguments from a method") + + Dim result = a + b + + Await Assert.That(result).IsEqualTo(c) + End Function + + + + Public Sub ClassDataSourceTest(dataClass As DataClass) + Console.WriteLine("This test can accept a class, which can also be pre-initialized 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") + End Sub + + + + Public Async Function CustomDataGenerator(a As Integer, b As Integer, c As Integer) As Task + Console.WriteLine("You can even define your own custom data generators") + + Dim result = a + b + + Await Assert.That(result).IsEqualTo(c) + End Function + + Public Shared Iterator Function DataSource() As IEnumerable(Of (a As Integer, b As Integer, c As Integer)) + Yield (1, 1, 2) + Yield (2, 1, 3) + Yield (3, 1, 4) + End Function + + End Class + +End Namespace \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.VB/Tests2.vb b/TUnit.Templates/content/TUnit.VB/Tests2.vb new file mode 100644 index 0000000000..2244bd7ef8 --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/Tests2.vb @@ -0,0 +1,32 @@ +Imports System +Imports TUnit.Core + + + +Public Class MoreTests + Private ReadOnly _title As String + + Public Sub New(title As String) + _title = title + End Sub + + + Public Sub ClassLevelDataRow() + Console.WriteLine(_title) + Console.WriteLine("Did I forget that data injection works on classes too?") + End Sub + + + Public Property DataClass As DataClass + + + + Public Sub Matrices( + a As Integer, + b As Boolean, + c As String) + 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.") + End Sub + +End Class \ No newline at end of file diff --git a/TUnit.Templates/content/TUnit.VB/Tests3.vb b/TUnit.Templates/content/TUnit.VB/Tests3.vb new file mode 100644 index 0000000000..4cadd2f0b9 --- /dev/null +++ b/TUnit.Templates/content/TUnit.VB/Tests3.vb @@ -0,0 +1,20 @@ +Imports System +Imports TUnit.Core + + + +Public Class AndEvenMoreTests + + Private ReadOnly _dataClass As DataClass + + Public Sub New(dataClass As DataClass) + _dataClass = dataClass + End Sub + + + Public Sub HaveFun() + Console.WriteLine(_dataClass) + Console.WriteLine("For more information, check out the documentation") + Console.WriteLine("https://tunit.dev/") + End Sub +End Class \ No newline at end of file diff --git a/TUnit.sln b/TUnit.sln index 7396e8fadd..be70af26c1 100644 --- a/TUnit.sln +++ b/TUnit.sln @@ -113,6 +113,13 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TUnit.TestProject.FSharp", EndProject Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "TUnit.TestProject.VB.NET", "TUnit.TestProject.VB.NET\TUnit.TestProject.VB.NET.vbproj", "{E0F6713B-3F3E-4335-B65F-69C9DE8FBA7C}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FSharp", "FSharp", "{03A13931-7DB3-4C3A-BB44-ACC9BE893708}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TestProject", "TUnit.Templates\content\TUnit.FSharp\TestProject.fsproj", "{76542D75-3835-82B7-6827-C5E5B6472EEB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VB", "VB", "{1C46F074-1BD0-4F64-B97A-F7485764B7C4}" +EndProject +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "TestProject", "TUnit.Templates\content\TUnit.VB\TestProject.vbproj", "{30004F07-1339-7426-8603-759816C431D7}" Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TUnit.Assertions.FSharp", "TUnit.Assertions.FSharp\TUnit.Assertions.FSharp.fsproj", "{D283B604-1860-4A6D-800A-A51849ACFEAF}" EndProject Global @@ -293,6 +300,14 @@ Global {E0F6713B-3F3E-4335-B65F-69C9DE8FBA7C}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0F6713B-3F3E-4335-B65F-69C9DE8FBA7C}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0F6713B-3F3E-4335-B65F-69C9DE8FBA7C}.Release|Any CPU.Build.0 = Release|Any CPU + {76542D75-3835-82B7-6827-C5E5B6472EEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76542D75-3835-82B7-6827-C5E5B6472EEB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76542D75-3835-82B7-6827-C5E5B6472EEB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76542D75-3835-82B7-6827-C5E5B6472EEB}.Release|Any CPU.Build.0 = Release|Any CPU + {30004F07-1339-7426-8603-759816C431D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30004F07-1339-7426-8603-759816C431D7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30004F07-1339-7426-8603-759816C431D7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30004F07-1339-7426-8603-759816C431D7}.Release|Any CPU.Build.0 = Release|Any CPU {D283B604-1860-4A6D-800A-A51849ACFEAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D283B604-1860-4A6D-800A-A51849ACFEAF}.Debug|Any CPU.Build.0 = Debug|Any CPU {D283B604-1860-4A6D-800A-A51849ACFEAF}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -346,6 +361,10 @@ Global {73EC87A5-577E-4149-B3B9-1C386AFBA2B1} = {0BA988BF-ADCE-4343-9098-B4EF65C43709} {9058BBB1-4561-4BBC-9BED-7075A50AFC14} = {0BA988BF-ADCE-4343-9098-B4EF65C43709} {E0F6713B-3F3E-4335-B65F-69C9DE8FBA7C} = {0BA988BF-ADCE-4343-9098-B4EF65C43709} + {03A13931-7DB3-4C3A-BB44-ACC9BE893708} = {1CE32FD7-4B3B-4639-B88F-67FB339461F2} + {76542D75-3835-82B7-6827-C5E5B6472EEB} = {03A13931-7DB3-4C3A-BB44-ACC9BE893708} + {1C46F074-1BD0-4F64-B97A-F7485764B7C4} = {1CE32FD7-4B3B-4639-B88F-67FB339461F2} + {30004F07-1339-7426-8603-759816C431D7} = {1C46F074-1BD0-4F64-B97A-F7485764B7C4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {109D285A-36B3-4503-BCDF-8E26FB0E2C5B} diff --git a/docs/docs/tutorial-assertions/fsharp.md b/docs/docs/tutorial-assertions/fsharp.md index 0e6ad4d66a..9826cc2601 100644 --- a/docs/docs/tutorial-assertions/fsharp.md +++ b/docs/docs/tutorial-assertions/fsharp.md @@ -6,13 +6,13 @@ sidebar_position: 10 As awaiting doesn't work quite the same in F#, the syntax instead looks like this: -```csharp +```fsharp do! check Assert.That(...).IsSomething() ``` So a test could look like: -```csharp +```fsharp member this.CheckPositive() = async { let result = 1 + 1 do! check (Assert.That(result).IsPositive())