23

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.

Community
  • 1
  • 1
Eamon Nerbonne
  • 47,023
  • 20
  • 101
  • 166

7 Answers7

11

Check out the PowerAssert library (example output below):

PAssert.IsTrue(() => x + 5 == d.Month * y);


System.Exception : IsTrue failed, expression was:

x + 5 == d.Month * y
| |   |  | |     | |
| |   |  | |     | 6
| |   |  | |     18
| |   |  | 3
| |   |  01/03/2010 00:00:00
| |   False
| 16
11

http://powerassert.codeplex.com/

Guy
  • 3,353
  • 24
  • 28
  • Well, the project doesn't seem completely mature, but the bugs I've encountered sofar have been trivial to fix, and I like the syntax - this looks nicer to use than Satisfyr. Thanks! – Eamon Nerbonne Dec 02 '10 at 15:52
  • 1
    Well, I like the idea behind power assert, but there were a few too many issues I encountered; I reimplemented the core idea as [ExpressionToCode](http://code.google.com/p/expressiontocode/) – Eamon Nerbonne Dec 31 '10 at 16:10
5

http://satisfyr.codeplex.com/

Uses lambda expressions exactly like you described. You don't even take on a binary dependency, just add a single source file corresponding to your unit test framework.

Cameron Jordan
  • 759
  • 3
  • 5
  • Though basically very similar to power assert, I think this option is a little less usable since (1) the error messages aren't quite as explicit, (2) the syntax fits less nicely into typical unit tests, (3) the lambda expressions have a parameter which means the actual name or contents of the expression that parameter was filled with is unavailable at test time. – Eamon Nerbonne Dec 02 '10 at 15:55
  • Glad you found something that works for you :) Personally satisfyr is a great fit for me since I can use it both in xUnit.net and MSTest. – Cameron Jordan Dec 02 '10 at 17:56
  • Actually, I'm using Power assert with xUnit too :-) - it just throws exceptions, so no special integration is needed - right? But yeah, the projects aren't different in most meaningful ways. – Eamon Nerbonne Dec 02 '10 at 22:37
  • 1
    link is **dead** – bradgonesurfing May 15 '17 at 05:27
5

There is actually a very good reason that NUnit provides it's own DSL rather than using normal C# expressions. It's that NUnit is supposed to work with any .NET language using the same syntax. That's not to say we can't have lambdas, just that we won't ever rely exclusively on any particular language feature.

Many of the ideas given will work and many of the third-party software solutions could be incorporated into NUnit, provided that their authors want to offer them. Of course, lots of folks prefer to keep their solutions separate and that's OK too. But talk to your favorite authors if you want them to collaborate more closely with NUnit.

In NUnit 2.5, you can use PredicateConstraint, which takes a lambda as its argument. However, the syntax is a bit limiting. The Matches keyword will work in the middle of an expression, so you can write...

Assert.That(someActual, Not.Matches( someLambda );

but doing it without the Not requires...

Assert.That(someActual, new PredicateConstraint( someLambda ));

And, of course, neither of these is as clean as the suggested syntax.

Everyone interested in this issue is welcome to join us on nunit-discuss where discussions about what should be in NUnit actually lead to action!

Charlie

  • Welcome to Stack Overflow! It's always good to see a developer whose name I quickly recognize here :) – Mark Rushakoff Dec 02 '10 at 22:39
  • 1
    Expressions aren't tied to C# - they're present in at least VB.NET too; and they are in any case a core component of LINQ and the DLR - so it's not a very limiting requirement. And of course, you can *always* use plain boolean assertions and have a DSL as a fallback - it's just, why not use the features available at least where possible. Also, Expressions aren't quite as fully featured as the full language and were even less so in .NET 3.5; so clearly this isn't something for maximally compatible code. – Eamon Nerbonne Dec 02 '10 at 22:41
  • 1
    @eamon: Let me give you an extreme example that illustrates my point. The == operator is a language feature. Of course it's matched by the same or similar syntax in lots of languages and can have slightly different semantics in each of them. So NUnit provides its own EqualTo method to provide identical semantics over all .NET languages that use it. No language-based implementation can ever _replace_ EqualTo, but you can still use those implementations with NUnit, so long as you're clear on the meaning. – Charlie Poole Dec 19 '10 at 19:22
  • It's my understanding that NUnit also wants to be compatible with pre-2.0 .Net. –  Dec 23 '10 at 19:34
2

Cone ( https://github.com/drunkcod/cone ) is a NUnit addin that works with 2.5.5 & 2.5.7 (other versions are only a recompile away) that gives you that capability along with a few other nifty features.

Torbjörn Gyllebring
  • 17,928
  • 2
  • 29
  • 22
2

(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.

Eamon Nerbonne
  • 47,023
  • 20
  • 101
  • 166
1

No one that I know of, but I think this can be added to the upcoming NUnit 3 wishlist.

Some work to that end done in #TestEx http://sharptestex.codeplex.com/ is being thought for inclusion, but you can add a blueprint/issue for the more general approach you are asking.

https://blueprints.launchpad.net/nunit-3.0

https://bugs.launchpad.net/nunit-3.0

Monoman
  • 721
  • 10
  • 12
0

The Visual Studio 2010 unit test framework has a CollectionAssert class which is usefull.

It also provides an Assert.IsTrue(bool) for generic cases that you craft yourself but none that use expressions;

BenCr
  • 5,991
  • 5
  • 44
  • 68