diff --git a/TUnit.Assertions.FSharp/TUnit.Assertions.FSharp.fsproj b/TUnit.Assertions.FSharp/TUnit.Assertions.FSharp.fsproj index 7eeceee31c..2c94708a04 100644 --- a/TUnit.Assertions.FSharp/TUnit.Assertions.FSharp.fsproj +++ b/TUnit.Assertions.FSharp/TUnit.Assertions.FSharp.fsproj @@ -6,6 +6,7 @@ + diff --git a/TUnit.Assertions.FSharp/TaskAssert.fs b/TUnit.Assertions.FSharp/TaskAssert.fs new file mode 100644 index 0000000000..3689e47d70 --- /dev/null +++ b/TUnit.Assertions.FSharp/TaskAssert.fs @@ -0,0 +1,15 @@ +module TUnit.Assertions.FSharp.TaskAssert + +open TUnit.Assertions.Core + +[] +module TaskAssertBuilder = + let taskAssert = task + +[] +module TaskAssertCEExtensions = + type TaskBuilderBase with + #nowarn "FS1204" + member inline x.Bind(assertion: IAssertion, continuation: Unit -> TaskCode<'TOverall, 'TResult2>) : TaskCode<'TOverall, 'TResult2> = + let task = assertion.AssertAsync() + x.Bind(task, continuation) diff --git a/TUnit.TestProject.FSharp/TUnit.TestProject.FSharp.fsproj b/TUnit.TestProject.FSharp/TUnit.TestProject.FSharp.fsproj index 5fce858d96..885b879f6a 100644 --- a/TUnit.TestProject.FSharp/TUnit.TestProject.FSharp.fsproj +++ b/TUnit.TestProject.FSharp/TUnit.TestProject.FSharp.fsproj @@ -18,6 +18,7 @@ + diff --git a/TUnit.TestProject.FSharp/TaskAssertTests.fs b/TUnit.TestProject.FSharp/TaskAssertTests.fs new file mode 100644 index 0000000000..21e8fc36cb --- /dev/null +++ b/TUnit.TestProject.FSharp/TaskAssertTests.fs @@ -0,0 +1,62 @@ +namespace TUnit.TestProject + +open System.Threading.Tasks +open TUnit.Assertions +open TUnit.Assertions.Extensions +open TUnit.Assertions.FSharp.TaskAssert +open TUnit.Core +open TUnit.TestProject.Library.Models + +type TaskAssertTests() = + + [] + [)>] + member _.IsInitialized_With_1_ClassDataSource(class1: InitializableClass) : Task = + taskAssert { + do! Assert.That(class1.IsInitialized).IsTrue() + } + + [] + [, typeof)>] + member _.IsInitialized_With_2_ClassDataSources(class1: InitializableClass, class2: InitializableClass) : Task = + taskAssert { + do! Assert.That(class1.IsInitialized).IsTrue() + do! Assert.That(class2.IsInitialized).IsTrue() + } + + [] + [, typeof, typeof)>] + member _.IsInitialized_With_3_ClassDataSources(class1: InitializableClass, class2: InitializableClass, class3: InitializableClass) : Task = + taskAssert { + do! Assert.That(class1.IsInitialized).IsTrue() + do! Assert.That(class2.IsInitialized).IsTrue() + do! Assert.That(class3.IsInitialized).IsTrue() + } + + [] + [, typeof, typeof, typeof)>] + member _.IsInitialized_With_4_ClassDataSources(class1: InitializableClass, class2: InitializableClass, class3: InitializableClass, class4: InitializableClass) : Task = + taskAssert { + do! Assert.That(class1.IsInitialized).IsTrue() + do! Assert.That(class2.IsInitialized).IsTrue() + do! Assert.That(class3.IsInitialized).IsTrue() + do! Assert.That(class4.IsInitialized).IsTrue() + } + + [] + [, typeof, typeof, typeof, typeof)>] + member _.IsInitialized_With_5_ClassDataSources(class1: InitializableClass, class2: InitializableClass, class3: InitializableClass, class4: InitializableClass, class5: InitializableClass) : Task = + taskAssert { + do! Assert.That(class1.IsInitialized).IsTrue() + do! Assert.That(class2.IsInitialized).IsTrue() + do! Assert.That(class3.IsInitialized).IsTrue() + do! Assert.That(class4.IsInitialized).IsTrue() + do! Assert.That(class5.IsInitialized).IsTrue() + } + + [] + [] + member _.FailingAssertion_ThrowsCorrectly() : Task = + taskAssert { + do! Assert.That(1 + 1).IsEqualTo(3) // Should fail + } diff --git a/docs/docs/assertions/fsharp.md b/docs/docs/assertions/fsharp.md index 5b10b7ce84..6709cc0f10 100644 --- a/docs/docs/assertions/fsharp.md +++ b/docs/docs/assertions/fsharp.md @@ -14,9 +14,9 @@ So a test could look like: ```fsharp member this.CheckPositive() = async { - let result = 1 + 1 - do! check (Assert.That(result).IsPositive()) - } + let result = 1 + 1 + do! check (Assert.That(result).IsPositive()) +} ``` F# is a lot more strict with type resolution when it comes to extension methods and method overloads. Because of that you may need to annotate the type for the assertions. @@ -24,23 +24,42 @@ F# is a lot more strict with type resolution when it comes to extension methods For example, ```fsharp - [] - [] - member _.Test3() = async { - let value = "1" - do! check (Assert.That(value).IsEqualTo("1")) - } - - [] - [] - member _.Throws1() = async { - do! check (Assert.That(fun () -> task { return new string([||]) }).ThrowsException()) - } - - [] - [] - member _.Throws4() = async { - do! check (Assert.That(fun () -> Task.FromResult(true)).ThrowsNothing()) - } - -``` \ No newline at end of file +[] +[] +member _.Test3() = async { + let value = "1" + do! check (Assert.That(value).IsEqualTo("1")) +} + +[] +[] +member _.Throws1() = async { + do! check (Assert.That(fun () -> task { return new string([||]) }).ThrowsException()) +} + +[] +[] +member _.Throws4() = async { + do! check (Assert.That(fun () -> Task.FromResult(true)).ThrowsNothing()) +} +``` + +## taskAssert expression + +For Task-based tests you can also use the taskAssert computation expression to avoid wrapping every assertion in check. + +To use it, open the namespace: + +```fsharp +open TUnit.Assertions.FSharp.TaskAssert +``` + +Inside a taskAssert block you can directly do! the assertion: +```fsharp +[] +[] +member _.Test3() = taskAssert { + let value = "1" + do! Assert.That(value).IsEqualTo("1") +} +```