Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Readable assertion messages on failure. #155

Merged
226 changes: 112 additions & 114 deletions src/FsUnit.MsTestUnit/FsUnit.fs
Original file line number Diff line number Diff line change
@@ -1,119 +1,117 @@
module FsUnit.MsTest

open System
open Microsoft.VisualStudio.TestTools.UnitTesting
open NHamcrest
open NHamcrest.Core
open System.Collections

let inline private assertThat(actual, matcher:IMatcher<'a>) =
if not (matcher.Matches(actual)) then
let description = new StringDescription()
matcher.DescribeTo(description)
let mismatchDescription = new StringDescription()
matcher.DescribeMismatch(actual, mismatchDescription)
raise (new AssertFailedException(sprintf "%s %s" (description.ToString()) (mismatchDescription.ToString())))

#if NETSTANDARD1_6
type Assert with
static member That'<'a> (actual, matcher:IMatcher<'a>) =
assertThat(actual, matcher)
#else
type Assert with
static member That<'a> (actual, matcher:IMatcher<'a>) =
assertThat(actual, matcher)
#endif

let inline should (f : 'a -> ^b) x (y : obj) =
let c = f x
let y =
match y with
| :? (unit -> unit) as assertFunc -> box assertFunc
| _ -> y
if box c = null then
module FsUnit.MsTest

open System
open Microsoft.VisualStudio.TestTools.UnitTesting
open NHamcrest
open NHamcrest.Core
open System.Collections

let inline private assertThat(actual, matcher:IMatcher<'a>) =
if not (matcher.Matches(actual)) then
let description = new StringDescription()
matcher.DescribeTo(description)
raise (new AssertFailedException(sprintf "%s %s" (description.ToString()) (sprintf "was %A" actual)))
CaptnCodr marked this conversation as resolved.
Show resolved Hide resolved

#if NETSTANDARD1_6
type Assert with
static member That'<'a> (actual, matcher:IMatcher<'a>) =
assertThat(actual, matcher)
#else
type Assert with
static member That<'a> (actual, matcher:IMatcher<'a>) =
assertThat(actual, matcher)
#endif

let inline should (f : 'a -> ^b) x (y : obj) =
let c = f x
let y =
match y with
| :? (unit -> unit) as assertFunc -> box assertFunc
| _ -> y
if isNull (box c) then
assertThat(y, Is.Null())
else
assertThat(y, c)


let inline shouldFail (f:unit->unit) =
let failed =
try
f()
false
with
| _ -> true
if not failed then
raise (new AssertFailedException("Method should fail"))


let equal expected = CustomMatchers.equal expected

let equivalent expected =
CustomMatchers.equivalent (fun e a -> CollectionAssert.AreEquivalent(e, a)) expected

let equalWithin (tolerance:obj) (expected:obj) = CustomMatchers.equalWithin tolerance expected

let not' (expected:obj) = CustomMatchers.not' expected

let throw (t:Type) = CustomMatchers.throw t

let throwWithMessage (m:string) (t:Type) = CustomMatchers.throwWithMessage m t

let be = CustomMatchers.be

let Null = CustomMatchers.Null

let Empty = CustomMatchers.Empty

let EmptyString = CustomMatchers.EmptyString

let NullOrEmptyString = CustomMatchers.NullOrEmptyString

let True = CustomMatchers.True

let False = CustomMatchers.False

let NaN = CustomMatchers.NaN

let unique = CustomMatchers.unique

let sameAs expected = CustomMatchers.sameAs expected

let greaterThan (expected:obj) = CustomMatchers.greaterThan expected

let greaterThanOrEqualTo (expected:obj) = CustomMatchers.greaterThanOrEqualTo expected

let lessThan (expected:obj) = CustomMatchers.lessThan expected

let lessThanOrEqualTo (expected:obj) = CustomMatchers.lessThanOrEqualTo expected

let endWith (expected:string) = CustomMatchers.endWith expected

let startWith (expected:string) = CustomMatchers.startWith expected

let haveSubstring (expected:string) = CustomMatchers.haveSubstring expected

let ofExactType<'a> = CustomMatchers.ofExactType<'a>

let instanceOfType<'a> = CustomMatchers.instanceOfType<'a>

let contain expected = CustomMatchers.contain expected

let haveLength n = CustomMatchers.haveLength n

let haveCount n = CustomMatchers.haveCount n

let matchList = CustomMatchers.matchList

let choice = CustomMatchers.choice

let ascending = CustomMatchers.ascending

let descending = CustomMatchers.descending

let inRange min max = CustomMatchers.inRange min max

assertThat(y, c)
let inline shouldFail (f:unit->unit) =
let failed =
try
f()
false
with
| _ -> true
if not failed then
raise (new AssertFailedException("Method should fail"))
let equal expected = CustomMatchers.equal expected
let equivalent expected =
CustomMatchers.equivalent (fun e a -> CollectionAssert.AreEquivalent(e, a)) expected
let equalWithin (tolerance:obj) (expected:obj) = CustomMatchers.equalWithin tolerance expected
let not' (expected:obj) = CustomMatchers.not' expected
let throw (t:Type) = CustomMatchers.throw t
let throwWithMessage (m:string) (t:Type) = CustomMatchers.throwWithMessage m t
let be = CustomMatchers.be
let Null = CustomMatchers.Null
let Empty = CustomMatchers.Empty
let EmptyString = CustomMatchers.EmptyString
let NullOrEmptyString = CustomMatchers.NullOrEmptyString
let True = CustomMatchers.True
let False = CustomMatchers.False
let NaN = CustomMatchers.NaN
let unique = CustomMatchers.unique
let sameAs expected = CustomMatchers.sameAs expected
let greaterThan (expected:obj) = CustomMatchers.greaterThan expected
let greaterThanOrEqualTo (expected:obj) = CustomMatchers.greaterThanOrEqualTo expected
let lessThan (expected:obj) = CustomMatchers.lessThan expected
let lessThanOrEqualTo (expected:obj) = CustomMatchers.lessThanOrEqualTo expected
let endWith (expected:string) = CustomMatchers.endWith expected
let startWith (expected:string) = CustomMatchers.startWith expected
let haveSubstring (expected:string) = CustomMatchers.haveSubstring expected
let ofExactType<'a> = CustomMatchers.ofExactType<'a>
let instanceOfType<'a> = CustomMatchers.instanceOfType<'a>
let contain expected = CustomMatchers.contain expected
let haveLength n = CustomMatchers.haveLength n
let haveCount n = CustomMatchers.haveCount n
let matchList = CustomMatchers.matchList
let choice = CustomMatchers.choice
let ascending = CustomMatchers.ascending
let descending = CustomMatchers.descending
let inRange min max = CustomMatchers.inRange min max
let ofCase case = CustomMatchers.ofCase case

let supersetOf expected = CustomMatchers.supersetOf expected
Expand Down
12 changes: 4 additions & 8 deletions src/FsUnit.NUnit/FsUnit.fs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
// TODO : Add license header
namespace FsUnit

namespace FsUnit

open System
open System.Diagnostics
open NUnit.Framework
open NUnit.Framework.Constraints
open CustomConstraints

//
[<AutoOpen>]
module TopLevelOperators =

Expand Down Expand Up @@ -40,7 +36,7 @@ module TopLevelOperators =
match y with
| :? (unit -> unit) -> box (TestDelegate(y :?> unit -> unit))
| _ -> y
if box c = null then
if isNull (box c) then
Assert.That(y, Is.Null)
else
Assert.That(y, c)
Expand Down Expand Up @@ -90,8 +86,8 @@ module TopLevelOperators =

let descending = Is.Ordered.Descending

let not' x =
if box x = null then NotConstraint(Null) else NotConstraint(x)
let not' x =
if isNull (box x) then NotConstraint(Null) else NotConstraint(x)

let inRange min max = RangeConstraint(min, max)

Expand Down
8 changes: 3 additions & 5 deletions src/FsUnit.Xunit/FsUnit.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,19 @@ type MatchException (expected, actual, userMessage) =
inherit AssertActualExpectedException(expected, actual, userMessage)

type Xunit.Assert with
static member That<'a> (actual, matcher:IMatcher<'a>) =
static member That<'a> (actual, matcher: IMatcher<'a>) =
if not (matcher.Matches(actual)) then
let description = new StringDescription()
matcher.DescribeTo(description)
let mismatchDescription = new StringDescription()
matcher.DescribeMismatch(actual, mismatchDescription)
raise (new MatchException(description.ToString(), mismatchDescription.ToString(), null))
raise (new MatchException(description.ToString(), (sprintf "%A" actual), null))

let inline should (f : 'a -> ^b) x (y : obj) =
let c = f x
let y =
match y with
| :? (unit -> unit) as assertFunc -> box assertFunc
| _ -> y
if box c = null then
if isNull (box c) then
Assert.That(y, Is.Null())
else
Assert.That(y, c)
Expand Down
15 changes: 11 additions & 4 deletions tests/FsUnit.MsTest.Test/beGreaterThanTests.fs
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
namespace FsUnit.Test
open Microsoft.VisualStudio.TestTools.UnitTesting
open FsUnit.MsTest
open NHamcrest.Core

[<TestClass>]
type ``be greaterThan tests`` ()=

[<TestMethod>] member test.
``11 should be greater than 10`` ()=
11 |> should be (greaterThan 10)

[<TestMethod>] member test.
``11.1 should be greater than 11.0`` ()=
``11,1 should be greater than 11,0`` ()=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why you replaced . in test names by ,?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tests with . doesn't show up in my test explorer. Should I undo this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in VS?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it already fixed microsoft/testfx#682

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in VS 16.6.2.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I discovered that tests with period in their name are shown in a separate section within the test explorer.
In the coming PR I will undo this, because they're still there. I'm not satisfied with the , or other sequences (e.g. ..) inside the test name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

11.1 |> should be (greaterThan 11.0)

[<TestMethod>] member test.
``9 should not be greater than 10`` ()=
9 |> should not' (be greaterThan 10)

[<TestMethod>] member test.
``9.1 should not be greater than 9.2`` ()=
``9,1 should not be greater than 9,2`` ()=
9.1 |> should not' (be greaterThan 9.2)

[<TestMethod>] member test.
``9.2 should not be greater than 9.2`` ()=
``9,2 should not be greater than 9,2`` ()=
9.2 |> should not' (be greaterThan 9.2)

[<TestMethod>] member test.
``9,2 should not be greater than 9,2 but message should be equal`` ()=
(fun () -> 9.2 |> should be (greaterThan 9.2))
|> fun f -> Assert.ThrowsException<AssertFailedException>(f)
|> fun e -> e.Message
|> should equal ("Greater than 9.2 was 9.2")
9 changes: 8 additions & 1 deletion tests/FsUnit.MsTest.Test/beSubsetOfTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type ``be subsetOf tests`` ()=
{4..8} |> should be (subsetOf {1..10})

[<TestMethod>] member test.
``1 to 10 should be subset of 4. 1 and 7`` ()=
``1 to 10 should be subset of 4, 1 and 7`` ()=
[|1..10|] |> should be (supersetOf [|4;1;7|])

[<TestMethod>] member test.
Expand All @@ -37,3 +37,10 @@ type ``be subsetOf tests`` ()=
``should fail on '1 to 11 should be subset of 1 to 10'`` ()=
shouldFail (fun () ->
[1..11] |> should be (subsetOf [1..10]))

[<TestMethod>] member test.
``11 should not be subset of 1 to 10 but message should be equal`` ()=
(fun () -> [11] |> should be (subsetOf [1..10]))
|> fun f -> Assert.ThrowsException<AssertFailedException>(f)
|> fun e -> e.Message
|> should equal ("Is subset of [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] was [11]")
8 changes: 7 additions & 1 deletion tests/FsUnit.MsTest.Test/equalTests.fs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
namespace FsUnit.Test
open Microsoft.VisualStudio.TestTools.UnitTesting
open FsUnit.MsTest
open NHamcrest.Core

type AlwaysEqual() =
override this.Equals(other) = true
Expand Down Expand Up @@ -92,4 +91,11 @@ type ``equal Tests`` ()=
[<TestMethod>] member test.
``None should equal None`` ()=
None |> should equal None

[<TestMethod>] member test.
``Ok "foo" should fail on equal Ok "bar" but message should be equal`` ()=
(fun () -> Ok "foo" |> should equal (Ok "bar"))
|> fun f -> Assert.ThrowsException<AssertFailedException>(f)
|> fun e -> e.Message
|> should equal ("Equals Ok \"bar\" was Ok \"foo\"")

7 changes: 7 additions & 0 deletions tests/FsUnit.MsTest.Test/haveLengthTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ type ``haveLength tests`` ()=
``Array with 1 item should fail to not have Length 1`` ()=
shouldFail (fun () -> [|1|] |> should not' (haveLength 1))

[<TestMethod>] member test.
``Array with 1 item should fail to have Length 2 but message should be equal`` ()=
(fun () -> [|1|] |> should haveLength 2)
|> fun f -> Assert.ThrowsException<AssertFailedException>(f)
|> fun e -> e.Message
|> should equal ("Have Length 2 was [|1|]")

// Seq
[<TestMethod>] member test.
``Seq with 1 item should fail to have Length 1`` ()=
Expand Down
Loading