views:

194

answers:

3

It's recognized that "One Assertion Per Test" in assertion. It is not good to write assertion like below:

  Assert((foo != null) && (bar != null));

The better chocie is:

  Assert(foo != null);
  Assert(bar != null);

The question is what if the assertion is:

  Assert((foo == null) || (foo.length == 0));

The relationship is OR instead of AND.

Is there any way to make "One Assertion per test" while keep the logic?

+1  A: 

Sure: one test ensures a null foo asserts, one ensures a non-null foo with 0 length also fails (and others check the cases[s] where foo is not null and has length != 0). How is it any hander than checking an AND?

Edit: pseudocode as requested...:

  should_assert(themethod(foo=null))
  fakefoo = fakewhatever(length=0)
  should_assert(themethod(foo=fakefoo))
  ...rest of tests w/foo not null, w/length != 0

e.g., in a Python unittest w/a still-pseudocode mock, this might be:

  self.assertRaises(AssertionError, theobj.themethod, null)
  fakefoo = mock.makeObj(length=0)
  self.assertRaises(AssertionError, theobj.themethod, fakefoo))
  ...rest of tests w/foo not null, w/length != 0
Alex Martelli
Can you please write pseudo code for it?
Morgan Cheng
sure, let me edit my answer to cover that..
Alex Martelli
I'm not familiar with python. But, I'm still confused.Can I translate it to below? Assert(foo == null); Assert(foo.length == 0);This doesn't look right.
Morgan Cheng
Uh? If you assert both that's an AND, so of course it doesn't look right... asserting an OR means, e.g., assert(A or B) -> if not A then assert B -- in Python or anywhere else!-)
Alex Martelli
or rather: if A then assert(False) else assert(B);-)
Alex Martelli
Got it.I'm using C# which might not be powerful as python. the signature of Assert is like below: "Assert(bool condition, string msg);"Is there any way to do it?
Morgan Cheng
Alex Martelli
+1  A: 

The idea behind the guideline is that you only test one logical thing (which may boil down to a few asserts in some cases) in one test. Therefore if a test fails, you know the exact reason why it failed and can zone in into the specific block of code in a snap. To borrow an example from this page, if the following test fails, I know something is wrong with how country is extracted/determined in the Address type.

public void testCountry() throws Exception {
        assertEquals("COUNTRY",  anAddress.getCountry());
    }

Compare this with the version of the test with multiple asserts, it could fail for multiple reasons (and unless you use helpful assert messages) you'd need to debug the test (yuck!).

I'd need to see your complete test. From what it see, it seems to be that you're checking a collection for a something-not-found scenario. In which case, the recommendation is to return an empty collection so that the clients don't have to check for null. Since your test is also a client, it's life is also made simpler : Assert.AreEqual (0, foo.length)

Gishu
Good answer! Unit test means testing **one** unit in **one** situation.
furtelwart
A: 

The problem could not in the assertion, but in the Arrange or Act part of the testcase: when you unit-test, you invoke a [small] piece of code in a controlled environment. That is to say that you should know how the software under test will behave, and thus, know whether it will return a null pointer, or an empty string. Every test shall have one expected result.

... Unless you're using your test against several functions/methods that behave differently, or some third-party code that appears to behave differently in different situations. If this is the case, the "One assertion per rule" is just a guideline, and you can use the assertion as shown is the question. If this test fails, it will mean that the returned foo is a non-empty string.

Or, you could create a function to test for empty strings that will also test if the string pointer is not null:

Assert(is_empty_string(foo));

Your language string class may provide this method.

philippe