Additional "Should" assertions

ShouldLookLike

The Should library has numerous extension methods for assertions. But what if you wanted to compare the properties of two objects? You might write a test like this:

[Test]
public void then_returns_the_expected_model()
{
     _account.ShouldEqual(new AccountViewModel
     {
          AccountNumber = 12345,
          CustomerName = "Atticus Finch",
          Balance = 5042.61
     });
}

This test will fail because .ShouldEqual() will perform a comparison on two separate instances of the same class. What we really want to happen is to compare the properties of the two instances of the AccountViewModel class to make sure they are all the same. SpecsFor includes the ShouldLookLike() extension method for this purpose. The ShouldLookLike() extension method uses the power of the ExpectedObjects library to compare two complex objects.

[Test]
public void then_it_returns_the_expected_model()
{
     _account.ShouldLookLike(new AccountViewModel
     {
          AccountNumber = 12345,
          CustomerName = "Atticus Finch",
          Balance = 5042.61
     });
}

This test will pass because ShouldLookLike() will compare each property of the model to check that the value is the same between the two instantiations.

But what if one of the properties of _account has a different value than what we expect? The test will fail, but especially with a much larger model, it could be difficult to tell which properties are not equal.

When the test fails, ShouldLookLike() will list the properties that are not equal so we quickly know where the problem is.

System.Exception : For AccountViewModel.Balance, expected [5042.61] but found [4872.57].

ShouldContain and ShouldNotContain

Sometimes you want to know if an enumerable contains an item matching some arbitrary criteria. For example, you may want to make sure that a collection of users contains at least one user with the name "John Doe." You could check for this using a combination of LINQ and Should, like so:

[Test]
public void then_john_doe_was_added()
{
     _addedUsers.Any(u => u.UserName == "John Doe").ShouldBeTrue();
}

However, if your spec fails, you won't get a very useful error message. You'll get a generic "Expected true, got false" error. It would be more useful if the failure message told you what it failed to find in the collection.

The ShouldContain extension method handles this same scenario, and it gives you a much better message if the expected item isn't found:

[Test]
public void then_john_doe_was_added()
{
    //Will output "Expected list containing an item matching 'u => u.UserName == "John Doe"', but item was not found.
		_addedUsers.ShouldContain(u => u.UserName == "John Doe");
}

You may also want to make sure that a particular item is not in a list. For example, what if we wanted to make sure Jane Doe was not in our list of users?

[Test]
public void then_jane_doe_was_not_added()
{
    //Will output "Expected list not containing an item matching 'u => u.UserName == "Jane Doe"', but item was found.
		_addedUsers.ShouldNotContain(u => u.UserName == "Jane Doe");
}

ShouldContainAll

Sometimes your specs will be verifying the contents of strings that are generated by your system under test, such as checking a log message, checking the contents of an E-mail, etc. If your test is too specific, it could fail when the message is reworded slightly. Usually, it's enough just to make sure that certain key pieces of information, such as the correct user name or date, are present in the string. With ShouldContainAll, you can easily check that a string contains one or more tokens:

[Test]
public void then_the_message_includes_the_date_and_the_users_name()
{
    _passwordResetText.ShouldContainAll("John Doe", "11/10/2014");
}