A fluent interface gone wrong, so wrong

In January I created a unit test helper called Predassert. The goal of this library was to make assertions more readable, both in code and in test results. I wanted to turn this:

Assert.AreEqual(3, theResult);

Into this:

Pred.Assert(theResult, Is.EqualTo(3));

And to turn this:

System.InvalidOperationException: Sequence contains no matching element

Into this:

Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.Fail failed. The collection contains no matching element.

  The property Name is not correct. Expected ThisOne, actual ThatOne.

It started out harmless enough. I created classes with names like “Is”, “Contains”, and “Has”. These had methods like “SameAs”, “That”, and “Property”. I was able to string together grammatically correct sentences that were at once predicates and assertions (hence the name). Things were fine, it’s the dress that makes you look fat, and I can quit anytime I want.

Then I paired with Paul Hammant at ThoughtWorks. I had to show him this:

Pred.Assert(result.Facts, Contains<Fact>.That(
    Has<Fact>.Property(fact => fact.Members, Contains<FactMember>.That(
        KindOf<FactMember, DataMember>.That(
            Has<DataMember>.Property(field => field.Name, Is.EqualTo("players")) &
            Has<DataMember>.Property(field => field.Type,
                Has<DataType>.Property(type => type.Cardinality, Is.EqualTo(Cardinality.Many)) &
                KindOf<DataType, DataTypeFact>.That(
                    Has<DataTypeFact>.Property(type => type.FactName, Is.EqualTo("User")) &
                    Has<DataTypeFact>.Property(type => type.IsPivot, Is.EqualTo(true))
                )
            ) &
            Has<DataMember>.Property(field => field.LineNumber, Is.EqualTo(4))
        )
    ))
));

When this test fails, this is the result.

Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException: Assert.Fail failed. The collection contains no matching element.

  The property Members is not correct. The collection contains no matching element.

  The property Type is not correct. The property IsPivot is not correct. Expected True, actual False.

How did it ever come to this?

After some gentle suggestions from Paul, the test looks like this.

string code =
    "namespace Reversi.GameModel; " +
    "                             " +
    "fact Game {                  " +
    "  publish User *players;     " +
    "}                            ";
Namespace result = ParseToNamespace(code);
Field players = result.WithFactNamed("Game").WithFieldNamed("players");
Assert.IsInstanceOfType(players.Type, typeof(DataTypeFact));
Assert.IsTrue(((DataTypeFact)players.Type).IsPivot,    "The players field is not a pivot.");

And the test failure reads:

Assert.IsTrue failed. The players field is not a pivot.

If you ever want to see the abomination that was Predassert, you will have to dig through the revision history of Correspondence.

Leave a Reply

You must be logged in to post a comment.