XNSIO
  About   Slides   Home  

 
Managed Chaos
Naresh Jain's Random Thoughts on Software Development and Adventure Sports
     
`
 
RSS Feed
Recent Thoughts
Tags
Recent Comments

Single Assert Per Unit Test: Myth

You are telling me, if I were unit testing a List class and I wrote tests like the following with 2 assert statements in them, then I’m violating xUnit testing “best practices”.

@Test
public void addingElementIncreasesSizeOfTheList() {
	assertEquals(0, list.size()); 
       //or assertListSizeIs(0); - define your custom assert statement
	list.add("Element");
	assertEquals(1, list.size()); // assertListSizeIs(1);
}

If so, how and why?

I understand that if I wrote a test like the following its not very communicative:

@Test
public void removeElementBasedOnItsIndexAndReduceSizeByOne() {
	list.add("Element");
	assertEquals("Element", list.remove(0));
	assertEquals(0, list.size());
}

in this case, it might be better to write 2 test instead:

@Test
public void removeElementBasedOnItsIndex() {
	list.add("Element");
	assertEquals("Element", list.remove(0));
}
 
@Test
public void reducesSizeByOneOnRemovingAnElement() {
	list.add("Element");
	assertEquals(1, list.size());
	list.remove(0);
	assertEquals(0, list.size());
}

Notice our goal was better communication and one of the tests we ended up (incidentally) with had just one assert statement in it (which is better than the previous test which was asserting 2 different things).

Our goal is not one assert statement per test. Our goal is better communication/documentation. Using the one-assert-per-test heuristic helps to achieve better communication. But splitting tests into more tests or deleting an important assert statement from a test just to avoid multiple assert statements in a test is mindless dogma.

Conclusion: One-Assert-Per-Test really means test one aspect/behavior in each test (and communicate that clearly in your test name). It does not literally mean, one test should have only one assert statement in it. Test one aspect/behavior in one test and related aspect/behavior can be tested in another test. Sometimes we need more than one assert statement to assert one aspect/behavior and its helps to add those assert statements in the test for better communication.

So don’t be afraid, go ahead and add that second or third assert statement in your test. Be careful not to fill your test with many asserts, it becomes difficult to understand and debug.

UPDATE:
Folks, I’m sorry for using a naive code example. I agree the example does not do justice to the point I’m trying to make.

@Robert, I certainly like your test. Much better.

Here is another naive example, looking forward to brickbats 😉

Let’s assume I’m building a RomanDigit class and I need to make sure that RomanDigits are map friendly, .i.e. they work correctly when added to maps. Following is a test for the same:

@Test
public void isMapFriendly() throws Exception {
	RomanDigit one = new RomanDigit('I', 1);
	RomanDigit anotherOne = new RomanDigit('I', 1);
	Map romanDigits = new HashMap();
	romanDigits.put(one, "One");
	romanDigits.put(anotherOne, "AnotherOne");
	assertEquals(1, romanDigits.size());
	assertEquals("AnotherOne", romanDigits.get(one));
	assertEquals("AnotherOne", romanDigits.get(anotherOne));
}

Another example: When subtracting RomanDigits, only powers of ten can repeat.

@Test
public void onlyPowerOfTenCanRepeate() throws Exception {
	assertTrue("I is a power of Ten and can repeat", romanDigit('I').canRepeat());
	assertFalse("V is not a power of Ten and should not repeat", romanDigit('V').canRepeat());
}

Is there a better way to write these tests so that I only need one assert statement per test?


    Licensed under
Creative Commons License