Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TUnit.Assertions.FSharp/TUnit.Assertions.FSharp.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<ItemGroup>
<Content Include="TUnit.Assertions.FSharp.props" />
<Compile Include="Extensions.fs" />
<Compile Include="TaskAssert.fs" />
</ItemGroup>

<ItemGroup>
Expand Down
15 changes: 15 additions & 0 deletions TUnit.Assertions.FSharp/TaskAssert.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module TUnit.Assertions.FSharp.TaskAssert

open TUnit.Assertions.Core

[<AutoOpen>]
module TaskAssertBuilder =
let taskAssert = task

[<AutoOpen>]
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)
1 change: 1 addition & 0 deletions TUnit.TestProject.FSharp/TUnit.TestProject.FSharp.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<Compile Include="ClassConstructorTest.fs" />
<Compile Include="ClassConstructorWithEnumerableTest.fs" />
<Compile Include="ClassDataSourceDrivenTests.fs" />
<Compile Include="TaskAssertTests.fs" />
<Compile Include="Tests.fs" />
</ItemGroup>

Expand Down
62 changes: 62 additions & 0 deletions TUnit.TestProject.FSharp/TaskAssertTests.fs
Original file line number Diff line number Diff line change
@@ -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() =

[<Test>]
[<ClassDataSource(typeof<InitializableClass>)>]
member _.IsInitialized_With_1_ClassDataSource(class1: InitializableClass) : Task =
taskAssert {
do! Assert.That(class1.IsInitialized).IsTrue()
}

[<Test>]
[<ClassDataSource(typeof<InitializableClass>, typeof<InitializableClass>)>]
member _.IsInitialized_With_2_ClassDataSources(class1: InitializableClass, class2: InitializableClass) : Task =
taskAssert {
do! Assert.That(class1.IsInitialized).IsTrue()
do! Assert.That(class2.IsInitialized).IsTrue()
}

[<Test>]
[<ClassDataSource(typeof<InitializableClass>, typeof<InitializableClass>, typeof<InitializableClass>)>]
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()
}

[<Test>]
[<ClassDataSource(typeof<InitializableClass>, typeof<InitializableClass>, typeof<InitializableClass>, typeof<InitializableClass>)>]
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()
}

[<Test>]
[<ClassDataSource(typeof<InitializableClass>, typeof<InitializableClass>, typeof<InitializableClass>, typeof<InitializableClass>, typeof<InitializableClass>)>]
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()
}

[<Test>]
[<Category("Fail")>]
member _.FailingAssertion_ThrowsCorrectly() : Task =
taskAssert {
do! Assert.That(1 + 1).IsEqualTo(3) // Should fail
}
65 changes: 42 additions & 23 deletions docs/docs/assertions/fsharp.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,52 @@ 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.

For example,

```fsharp
[<Test>]
[<Category("Pass")>]
member _.Test3() = async {
let value = "1"
do! check (Assert.That<string>(value).IsEqualTo("1"))
}

[<Test>]
[<Category("Fail")>]
member _.Throws1() = async {
do! check (Assert.That<string>(fun () -> task { return new string([||]) }).ThrowsException())
}

[<Test>]
[<Category("Pass")>]
member _.Throws4() = async {
do! check (Assert.That<bool>(fun () -> Task.FromResult(true)).ThrowsNothing())
}

```
[<Test>]
[<Category("Pass")>]
member _.Test3() = async {
let value = "1"
do! check (Assert.That<string>(value).IsEqualTo("1"))
}

[<Test>]
[<Category("Fail")>]
member _.Throws1() = async {
do! check (Assert.That<string>(fun () -> task { return new string([||]) }).ThrowsException())
}

[<Test>]
[<Category("Pass")>]
member _.Throws4() = async {
do! check (Assert.That<bool>(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
[<Test>]
[<Category("Pass")>]
member _.Test3() = taskAssert {
let value = "1"
do! Assert.That(value).IsEqualTo("1")
}
```
Loading