Question

I am trying to combine basic Design by Contract (implemented by macros, which use the built-in assert function) and Google Test unit testing in an application.

So, for example, I have the following code:

AppFavorite* AppFavorites::Add(const UnicodeString& link)
{
    REQUIRE(!link.IsEmpty());

    ...
}

Now, I can't have the following test in my unit tests, because the IDE aborts when reaching the assert (REQUIRE(!link.IsEmpty());):

TEST(AppFavoritesTest, AddEmpty)
{
    AppFavorites favorites;
    ASSERT_THROW(favorites.Add(L""), std::invalid_argument);
}

So, my question is should I either:

  1. Never test for conditions, covered by contracts, or
  2. Disable somehow the contract checking during the unit tests?
Was it helpful?

Solution

You need to decide whether passing an empty string to that function is undefined behaviour or whether it's contract guarantees that it throws an exception if passed an empty string.

It sounds like your intent is for it to be undefined behaviour, i.e. the contract says nothing about what will happen if an empty string is passed. In that case, the easiest way to test the validation of your contract is to build your unit tests for negative testing as a special build with REQUIRE modified to throw some 'precondition violated' exception, which you would then test for with ASSERT_THROW

I highly recommend watching John Lakos' talk on Defensive Programming from ACCU 2011, it covers exactly this problem

OTHER TIPS

Design by Contract defines laws. Every use of your software must comply with these laws - included its unit testing. Unit testing tests that, provided that the software satisfies the law, it also does what you want it to do.

So you should test your software only with the preconditions satisfied.

In public layers which could be used by any user in a wrong way it's better to leave precondition checks activated, or to protect your inputs with a special input validation layer which would then be tested with a wide range of possible input data, including what your internal logic would deem as a precondition violation - but then what you will test is the protection layer.

I find software build following this strategy much more robust and maintainable in the long run.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top