Using NHamcrest with NUnit or XUnit

NHamcrest is supported out of the box with MbUnit, but there’s nothing stopping you using it with any other framework.

You just need to write the shim code, i.e. Assert.That.

For example, with NUnit it would look something like this:

public static void That<T>(T actual, IMatcher<T> matcher, string message, params object[] args)
{
	if (matcher.Matches(actual))
		return;
	
	var writer = new TextMessageWriter(message, args);

	WriteExpected(matcher, writer);

	WriteActual(actual, matcher, writer);

	throw new AssertionException(writer.ToString());
}

private static void WriteExpected(ISelfDescribing matcher, TextWriter writer)
{
	writer.Write(TextMessageWriter.Pfx_Expected);
	var description = new StringDescription();
	matcher.DescribeTo(description);
	writer.Write(description.ToString());
	writer.WriteLine();
}

private static void WriteActual<T>(T actual, IMatcher<T> matcher, TextWriter writer)
{
	writer.Write("  But ");
	var mismatchDescription = new StringDescription();
	matcher.DescribeMismatch(actual, mismatchDescription);
	writer.Write(mismatchDescription.ToString());
	writer.WriteLine();
}

For XUnit:

public static void That<T>(T actual, IMatcher<T> matcher)
{
	if (matcher.Matches(actual))
		return;

	var description = new StringDescription();
	matcher.DescribeTo(description);

	var mismatchDescription = new StringDescription();
	matcher.DescribeMismatch(actual, mismatchDescription);

	throw new MatchException(description.ToString(), mismatchDescription.ToString(), null);
}

public class MatchException : AssertActualExpectedException
{
	public MatchException(object expected, object actual, string userMessage) : base(expected, actual, userMessage)
	{
	}
}

And, for completeness, here’s the MbUnit version:

        public static void That<T>(T item, IMatcher<T> matcher, string messageFormat, params object[] messageArgs)
        {
            AssertionHelper.Verify(() =>
            {
                if (matcher.Matches(item))
                    return null;

                var description = new StringDescription();
                var mismatchDescription = new StringDescription();

                matcher.DescribeTo(description);
                matcher.DescribeMismatch(item, mismatchDescription);

                return new AssertionFailureBuilder("Expected " + description)
                    .SetMessage(messageFormat, messageArgs)
                    .AddLabeledValue("Expected", description.ToString())
                    .AddLabeledValue("But", mismatchDescription.ToString())
                    .ToAssertionFailure();
            });           
        }

Assert.Throws with NHamcrest

NHamcrest is a C# port of Hamcrest, a popular matching library. I recently added support for Assert.Throws:

    [Test]
    public void Throws()
    {
        Assert.That(() => { throw new ArgumentNullException(); }, 
            Throws.An<ArgumentNullException>());

        // with a predicate
        Assert.That(() => 
            { 
                throw new ArgumentNullException("message", new Exception()); 
            }, Throws.An<ArgumentNullException>()
            .With(e => e.Message == "message" && e.InnerException.GetType() == typeof(Exception)));
    }