Writing a custom assertion for SharpTestEx

Actually SharpTestEx is my favorite way to make assertions in Unit testing. It has a lot of advantages, first of all it permits to write really clear assertions, then it works on the main Unit testing framework, so I can use the same assertion syntax for nunit and for MStest or MbUnit etc etc.

Another cool advantages is how simple is to extend the syntax, the IEnumerableConstraint has the Contain assertion to verify that an element is contained in a IEnumerable sequence of objects. Now I want to be able to write a ContainAny that accepts a lambda to specify a condition that must be satisfied by at least one of the elements of the collection.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public static IAndConstraints<IEnumerableConstraints<T>> Contain<T>(
this IEnumerableConstraints<T> constraint,
Func<T, Boolean> checkFunction)
{
constraint.AssertionInfo.AssertUsing(
new Assertion<IEnumerable<T>, Func<T, Boolean>>(
"Contain",
checkFunction,
a => (a != null) && a.Any(checkFunction),
mi =>
string.Format("{0} {1} {2} {3}.{4}",
"Sequence",
"Should",
mi.AssertionPredicate,
Messages.FormatValue(mi.Expected),
mi.CustomMessage)));
return ConstraintsHelper.AndChain(constraint);
}

The code is really simple, it is based on the Assertion<Source, Func> class that permits to send to the assertion engine an assertion that verify something. The third parameter of the Assertion constructor accepts a predicate that will be used to validate the assertion itself. In our example I use the Any linq method to verify that at least any of the element of the collection satisfy the original lambda.

now I want to verify that a list of uri does not contain any element with mail in the address

1
list.Should().Not.ContainAny(u => u.AbsoluteUri.Contains("mail"));

Simple and readable. In case of failure the error is.

1
failed: SharpTestsEx.AssertException : Sequence Should Not Contain System.Func`2[System.Uri,System.Boolean].

Since this is really not so clear, I changed the assertion function a little bit.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public static IAndConstraints<IEnumerableConstraints<T>> ContainAny<T>(
this IEnumerableConstraints<T> constraint,
Expression<Func<T, Boolean>> checkFunction)
{
constraint.AssertionInfo.AssertUsing(
new Assertion<IEnumerable<T>, Expression<Func<T, Boolean>>>(
"Not contain any element that satisfy predicate",
checkFunction,
a => (a != null) && a.Any(checkFunction.Compile()),
mi =>
string.Format("{0} {1} {2} {3}.{4}",
"Sequence",
"Should",
mi.AssertionPredicate,
Messages.FormatValue(mi.Expected),
mi.CustomMessage)));
return ConstraintsHelper.AndChain(constraint);
}

The only difference is that now the function accepts an Expression tree, and uses Compile() method to create a real Function<T, Boolean> method used to search into the sequence. Now when the test fails it writes:

1
failed: SharpTestsEx.AssertException : Sequence Should Not Not contain any element that satisfy predicate u => u.AbsoluteUri.Contains("mail").

I really love SharpTestEx.

alk.