Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to apply "One Assertion Per Test" for OR relation condition

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?

like image 946
Morgan Cheng Avatar asked Jan 23 '23 13:01

Morgan Cheng


2 Answers

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)

like image 70
Gishu Avatar answered Jan 29 '23 23:01

Gishu


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.

like image 40
philant Avatar answered Jan 29 '23 23:01

philant