Friday, July 16, 2010

Be more assertive when unit testing (and not when challenging me)

I tweeted this today.
A test without an assert is not a test. It leaves the intended behaviour as completely ambiguous.
Apparently I'm wrong. Some people disagreed. They were mistaken.
Let's examine their arguments.

Argument #1: Name the test method clearly enough and you don't need an assert?

public void Should_not_throw_when_doing_that_thing()
{
        var obj = new MyObj();
        var result= obj.doThatThing();       
}

To me this this has a huge gap missing in it. I'm a fan of the AAA pattern when constructing tests. Above we are only doing the Arrange and Act part.  This is why I'm not a fan of the [ExpectedException] attribute. There is no assert within the body of the message. It just doesn't read as I expect to be.

Argument #2: A test can contain no assertions, if you are mocking interactions.


[Test]
public void WhenDoingSomeThingWithAnotherThingThatWillOccur()
{
    var someThing = MockRepository.GenerateStub();
    var anotherThing = MockRepository.GenerateStub();

    someThing.Stub(x => x.Do(1)).Return(2);

    new myObj(someThing, anotherThing).Do(1);

    notificationSender.AssertWasCalled(//blah);
}

Ok this is a good point but when you are interaction testing you are still asserting that a behaviour is true. Its even there in the code.

As you can tell I'm not convinced. Can anyone provide a compelling reason to leave asserts out of tests?




2 comments:

workmad3 said...

I'd agree with you here. The only vaguely compelling 'test without an assertion' would be one that just checks something doesn't throw an exception... but that behaviour will *already* be tested with your test that asserts the result is what you expect, so in order to DRY your tests out, that test would be thrown away as useless or even potentially damaging - after all, it could be artificially increasing test coverage reports.

Rob Cooper said...

I'm with you dude!

Argument #1: It's not just about what the asser, err, asserts, but also the feedback that runner gives you in doing the assert. Maybe it is just me, but when testing, I respond much better to "expected X but got Y" - that immediately makes my brain start asking "why Y?" :)

Argument #2: Why test the interactions? The interactions MUST lead to something (even if just a state change in another object). Ultimately, in most loosely coupled designs, you shouldn't need to test interactions, because the interactions are against an interface - which you should have no idea in how that interface is implemented, right? ;)

After a good chat with Seb Lambla about mockless testing, it really got me thinking.. Now, I test without mocks and don't make assumptions about interactions.. Result? Tests are easier to read (no mocking framework syntax and I create lightweight static factories to create my stubs) and it makes sure I am keeping my code ignorant of interface implementations..

Just my 10 bits :)