Try fast search NHibernate

14 April 2009

NUnitEx: assertion.Should().Satisfy(lambda);

In the first post about NUnitEx, Liviu has left a comment with this assertion:

CustomAssert(()=> DateTimeToday < DateTime.Now);

It sound very interesting from someone of us and Simone Busoli began an experiment named “Language Integrated NUnit” (LinUnit). The main concepts behind LinUnit are :

  • pure .NET based assertion
  • assertions easy to extend

LinUnit is now part of NUnitEx.

Examples

const string somethig = "something";

somethig.Should()
.Satisfy(x => x.Contains("some"));

somethig.Should()
.Satisfy(x => !x.Contains("also"));

somethig.ToUpperInvariant().Should()
.Satisfy(x => x.ToUpperInvariant().Contains("SOME"));

somethig.Should()
.Satisfy(x => x.StartsWith("so") && x.EndsWith("ing") && x.Contains("meth"));

somethig.Should()
.Satisfy(x => !x.StartsWith("ing") && !x.EndsWith("so") && !x.Contains("body"));

As you can see the parameter of Satisfy method is a pure C# lambda.

Note that the matter here is the assertion message; for example given this

const string somethig = "something";
somethig.Should()
.Satisfy(x => x.Contains("also"));

the failing message say:

Expected: "x.Contains("also")"
But was:  "something"

One more example using Linq extensions

var ints = new[] { 1, 5, 5, 3 };

ints.Should()
.Satisfy(x => x.SequenceEqual(new[] { 1, 5, 5, 3 }));

The implementation of  “Language Integrated NUnit”, available in NUnitEx, need some more improvement in order to use conventional NUnit constraints, where available, and more complex expressions (basically an improvement of the expression visitor).

Which syntax I should use ?

Well… this is exactly the news. You can use the syntax you have more feeling in the place you think is the best place.

For example for action-exception I prefer this syntax

Assert.Throws<ArgumentNullException>(() => new AClass(null))
.ParamName.Should().Be.Equal("obj");

I’m using NUnitEx in some projects and what I have noticed is that I’m not using Assert.That(…) anymore. For sure, at the begin, you may have some problem to identify the assertion because you can’t easy find “Assert”, with its different color, in the source code but believe me is only a matter of time. The advantage of “Should” with the intellisense helping you will be clear from the first usage.

Entschuldigen, diese sache kann ich nicht lesen

What mean “readability” ? What is readable ?

Probably the most readable is your natural language.

In Italian
{1, 2, 3} dovrebbe avere la stessa sequenza di {1, 2, 3} ed essere un sub-insieme di {5,1,2,3}

In Spanish
{1, 2, 3} tendría que tener la misma secuencia de {1, 2, 3} y ser un subconjunto de {5,1,2,3}

In English
{1, 2, 3) should have same sequence as {1, 2, 3} and be a subset of {5,1,2,3}

In C#
(new[] {1,2,3}).Should().Have.SameSequenceAs(new[] {1,2,3}).And.Be.SubsetOf(new[] {5,1,2,3})

In the natural language we are using spaces to separate words, but in C# we can’t so, in general, we are using the ‘_’ (underscore) or ‘.’ (dot).

In my opinion something like ShouldNotBeNullOrEmpty is less readable than

Should().Not.Be.Null().And.Not.Be.Empty()

A dot-separated-syntax help to separate each word and give you the chance to be helped by intellisense (and obviously is better extensible). A one-PascalCase-syntax mean that you should remember many words of the assertion name before the intellisense can help you.

When my wife (she are using the PC for others matters) read 5.Should().Be.LessThan(10) said : “seriously your work is ask, to the PC, such kind of things” (well… exactly she said “¿me estas cargando?”); what was interesting is that, even a no C# expert, can read it.

When the implementation of LinUnit-syntax will be more complete, probably, many .NET developer will feel better with it because it is pure .NET and you don’t need to remember which is the assertion.


kick it on DotNetKicks.com

4 comments:

  1. I still hate that you should use () for C# to be able to compile...excepting this i think this can help readability of tests, although i didn't use it and i'm still not sure it will be better than the traditional asserts...
    I'll let you know after trying it :)

    ReplyDelete
  2. The syntax is terrific. However, I found a very little problem with this:

    "foo".Should().Be.Equals("bar");

    Note that I wrote inadvertently "Equals" and not "EqualTo". This is very very very similar. IMHO: Two options for me override "Equals" or add obsolete attributte.

    ReplyDelete
  3. what do you mean with "The syntax is terrific" ?

    The old impl was "Equal" and not "Equals". I have tried to remove System.Object's methods from intellisense but, so far, without lucky.

    ReplyDelete
  4. terrific: tremendous, wonderful, wondrous.

    Yes, I know but if you add something like this:

    [Obsolete]
    public override bool Equals(object obj)
    {
    return base.Equals(obj);
    }

    If you write -> "Should().Be.Eq.." , "Equals" will appear strikethrough....And if you still try to use, then you will have a compiler warning.

    I know, Equals is not "obsolete", and "obsolete" have another meaning.

    ReplyDelete