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")
+}
+```