views:

48

answers:

3

Hi, I'm learning TDD with VB.NET and NUnit. I want to know what's the best thing to do: Use a lot of Assert methods inside of a test method or use a assert per method?

This is my code. Thank you.

Imports NUnit.Framework

<TestFixture()> _
Public Class CalculatorTest
<Test()> _
Public Sub TestAdd()
    Dim calculator As Calculator = New Calculator()

    Assert.AreEqual(2, calculator.sum(1, 1))
    Assert.AreNotEqual(3, calculator.sum(2, 2))
    Assert.AreEqual(-1, calculator.sum(0, -1))
        Assert.AreNotEqual(3, calculator.sum(1, 1))
    End Sub
End Class
+2  A: 

The generally accepted 'Best Practice' is one assert per test. (According to Roy Osherove)

However, this particular test may be done a little more simply with NUnit using TestCases:

<Test()> _
<TestCase(1, 1, 2)> _
<TestCase(1,-1, 0)> _
<TestCase(0,-1,-1)> _
Public Sub Calculator_Add_ReturnsExpectedResult(Integer a, Integer b, Integer expected)
    Dim calculator As Calculator = New Calculator()

    Assert.AreEqual(expected, calculator.sum(a, b))
End Class

Also note the naming I used there, in order to clarify exactly what the test is testing.

The principal behind the "One Assert Per Test" practice is that you want a failed test to mean something very specific. That is, each test should tell you if a single specific thing is working.

John Gietzen
<TestCase(1, 1, 2)> _ : What does it mean? Thank you.
Thomas
It means that it will call your test function several times, each with different inputs (as specified in the annotation). In this case it will call it three times, first with (1,1,2) then with (1,-1,0) and finally with (0,-1,-1).
Martin Wickman
Thank you, i got it!
Thomas
Note that as separate test cases, like this, each assertion gets run and reported, regardless of whether the assertion before it passed. So you have a more complete failure report if anything went wrong. In the case of assertions within one method, if the first assertion fails, you won't know the outcome of the others.
Carl Manaster
A: 

This is an interesting debate, and can come down to a matter of style. I like Roy Osherove's view, that you should only have one assert per unit test.

Read his in-depth discussion of this issue here: http://weblogs.asp.net/rosherove/archive/2006/10/04/Avoid-multiple-asserts-in-a-single-unit-test_3A00_-revisited.aspx

Also, check this out: http://msdn.microsoft.com/en-au/magazine/cc163665.aspx

Sam
@Sam This isn't really a "debate" and more of a style discussion. I prefer multiple asserts in each test, and find that most real world unit tests will require more than one assert to clear all assumptions for a given test.
Lucas B
Thank you, i will read it!
Thomas
+5  A: 

A better way to think about it is to test one thing at a time. Use as many asserts as necessary to test that one thing, but typically only one. Multiple asserts can be a sign that you are testing more than one thing at a time but it's not, in my opinion, a hard and fast rule. The best guide is that you don't want to create dependencies in your tests between concepts that are independent.

In your example you are actually testing 4 things, though you actually probably only need two of them since they cover the same ground. I'd suggest testing what happens when you add two positive numbers, two negative numbers, and a negative and a positive with negative and positive results. Then I'd think about mathematical properties and test commutativity and the additive identity (zero). Finally, I'd test the boundary conditions -- positive and negative overflow, etc. Note, this may or may not be comprehensive, i.e., I think I've covered the bases, but I'm not trying too hard to be exhaustive; I just want to illustrate how you'd go about thinking about what tests to write and, yes, I'd make each of these separate tests with a single assert.

For something more complex, you may have more than one assert that tests the same "thing" -- e.g., you may want to check that a row is properly inserted in the DB with a given set of inputs. I think it's perfectly acceptable to test that all columns have their proper value in a single test, rather than test each property individually. Others may differ, but I don't think that in this case you are creating any dependencies by testing that all properties have their correct values because the insert is an atomic action.

tvanfosson
A great explanation. Thank you!
Thomas