Basically NUnit, xUnit, MbUnit, MsTest and the like have methods similar to the following:
Assert.IsGreater(a,b)
//or, a little more discoverable
Assert.That(a, Is.GreaterThan(b))
However, there are a limited number of such comparison operators built-in; and they duplicate the languages operators needlessly. When I want anything even slightly complex, such as...
Assert.That(a.SequenceEquals(b))
I'm often either left digging through the manual to find the equivalent of the expression in NUnit-speak, or am forced to fall-back to plain boolean assertions with less helpful error messages.
C#, however, integrates well with arbitrary Expressions - so it should be possible to have a method with the following signature:
void That(Expression<Func<bool>> expr);
Such a method could be used to both execute the test (i.e. validate the assertion) and to also provide less-opaque diagnostics in case of test failure; after all, an expression can be rendered to pseudo-code to indicate which expression failed; and with some effort, you could even evaluate failing expressions intelligently to give some clue of the value of subexpressions.
For example:
Assert.That(()=> a == b);//could inspect expression and print a and b
Assert.That(()=> a < b && b < c);
//could mention the values of "a<b" and "b<c" and/or list the values of a, b, and c.
At a minimum, it would make the use of a parallel language for expressions unnecessary, and in some cases it might make failure messages more useful.
Does such a thing exist?
Edit: After trying (and liking!) Power Assert, I ended up reimplementing it to address several limitations. My variant of this is published as ExpressionToCode; see my answer below for a list of improvements.
(Original Poster here)
I love PowerAssert.NET's simple syntax and messages, but the C# it produces has many issues. In particular, it doesn't support several expression features, and it doesn't add parentheses where required by operator precedence/associativity. After fixing a few bugs (and reporting them to the author) I found it'd be simpler to fix with a different approach, and to reimplement it from scratch.
The usage is similar:
PAssert.That(()=>
Enumerable.Range(0,1000).ToDictionary(i=>"n"+i)["n3"].ToString()
== (3.5).ToString()
);
Outputs:
PAssert.That failed for:
Enumerable.Range(0, 1000).ToDictionary(i => "n" + (object)i)["n3"].ToString() == 3.5.ToString()
| | | | | |
| | | | | "3.5"
| | | | false
| | | "3"
| | 3
| {[n0, 0], [n1, 1], [n2, 2], [n3, 3], [n4, 4], [n5, 5], [n6, 6], [n7, 7], [n8, 8], [n9, 9], ...}
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...}
Improvements over PowerAssert.NET:
- Supports static field and property access
- Supports more operators, such as logical and bitwise negation.
- Recognizes C# indexer use (e.g.
dict["mykey"]==3) - Adds parentheses where required by operator precedence and associativity (e.g.
() => x - (a - b) + x * (a + b)is correctly regenerated) - Generates valid numeric and other constant literals including escapes and suffixes as appropriate for the expression type (e.g.
1m + (decimal)Math.Sqrt(1.41)) - Supports C# syntactic sugar for object initializers, object member initializers, list initializers, extension methods, amongst other things.
- Uses the same spacing rules Visual Studio does by default.
- Supports nested Lambdas
- Expands generic type instances into normal C#; e.g.
Func<int, bool> - Supports several expression tree constructs not yet used by C# 4.0 embedded expressions.
The resultant project (with unit tests) is hosted in google code under the name ExpressionToCode - I hope it's useful to others.