Use Assertions

Understand WhatAreAssertions and what they're good for, and then use them.


The logic in "DoNotUseAssertions" is faulty.

When an assertion fails, the program halts, and a programmer figures out what's wrong, and fixes it. Then the assertion doesn't fail anymore. It's important to understand that the code is not supposed to handle the error - a person is.

It is also important to remember that standard operating procedure for assertions is to turn them off before doing a build that will be sent to real customers; In this case I'd argue that BairsLaw does apply, but the conclusion that assertions should not be used by the programmer does not follow.

I should also mention not everybody uses UnitTests, and they are not required to ship good software. In a development process that relies heavily on human testing, assertions might well increase the rigor of the testing.

-- CurtisBartley

Can't we view assertions as merely an early attempt to have UnitTests that are embedded in the code? Assertions provide a simple way to insert a stub test for the calling function(s).


Logical assertions can easily be used to check the sanity of parameter values, but they're good for more than that: Use logical assertions to verify that all variables are initialized properly for your algorithm to operate correctly. After the algorithm runs, use assertions to verify that it ran correctly.

Example: In a function, I've built a linked list of results that correspond to an input array of requests. Now I'll apply some algorithm that does something to the request and result pairs. The algorithm is simple, but would fail in subtle or disastrous ways if the list and array were not the same length. But I know they're the same length; I just wrote the code that builds them. But how do I know I didn't make a silly coding mistake? How do I know that the next "N" entry-level maintenance programmers won't make similarly silly coding mistakes? Simple: Right before the loop, I assert that the two sets have equal length. Then, silly little coding errors and logical errors in thinking will become immediately obvious during UnitTesting. Better yet, if the assertion fails, it will be dramatically easier (and hence less time consuming and expensive) to determine what went wrong, and fix it. Without the assertion, the subtle or disastrous errors would exhibit symptoms in other parts of the code, requiring substantially greater effort to track down the actual cause.

Example (continued): After looping through the array and list simultaneously, and terminating when (say) the next pointer is NULL, I know that I'm also at the end of the array. If I weren't at the end of the array, then I'd know that my code was written incorrectly. So I assert that my array index is at the end. (I could terminate the loop based on the array index, but then I'd want to be sure the next pointer was NULL - by asserting so. I could be excessively paranoid, and check both in the while condition of my loop, but then I'd have to check both in an assert after the end, or risk loss of data.)

There is no way that UnitTests could "test" the conditions I'm asserting: There is no combination of inputs that would produce the erroneous state; only an error in coding can produce it. So, during development testing, I use asserts to catch common coding errors and to help debug them. In production, I drop the overhead of all the extra "can never happen" testing. (If it could reasonably happen, then I shouldn't use an assert; I should check the condition with an "if" and then throw an exception.)

-- JeffGrigg

How about refactoring your code so that you are using one data structure, rather than a list and an array? The error couldn't occur if you do that.

True, it's generally better to have an array of objects than artificially synchronized arrays of attributes. But there are also situations for keeping them separate. If the input is a set of commands or SQL queries to execute, and the output is the set of results to return, then mixing the input with the output may mean that you'll have to rework all the data again to get the desired output. And all this processing does nothing but create more opportunities for useful assertions: Like, after copying the input statements/queries to the new list of objects for more convenient processing, you'd want to assert that you still have the same number of objects as you had queries, wouldn't you? If you had lost some, then something must have gone dreadfully wrong. -- JeffGrigg

To some extent, OnceAndOnlyOnce by reducing redundancy tends to fix automatically problems you might otherwise catch by assertions. However, there's still plenty of room for checks. -- MartinPool

I find assertions particularly valuable to test pre-conditions. Note: this is not the same as checking parameters. All of the arguments may well be just fine, but if the object is not ready to have you call a particular method, you have a coding error (in the caller). -- RussellGold

Assertions are related to type checking. Both assertions and type checking are SeatBelts? you can wear to protect yourself from bugs. If you don't want them you don't have to UseAssertions and you can use a dynamically typed language like PythonLanguage. -- OrenTirosh

Assertions aren't SeatBelts? - they're CrashTestDummies?. SeatBelts? are DefensiveProgramming. -- ZygoBlaxell


I habitually assert False in a "Case Else". On more than one occasion this has caught people passing in data that the routine wasn't intended to handle. -- DominicCronin

I habitually use polymorphism and LawOfDemeter. I don't have to worry about "case else" ;)


Unless you are saying your testing is perfect you need asserts to catch runtime problems. UnitTests are not system tests and lots of problems are found at system test time. They would not be found without DesignByContract/asserts.


There is no way that UnitTests could "test" the conditions I'm asserting.

The point being the UnitTests almost always test to make something works. They don't catch programmer error or system level effects not reproducible in a UnitTest.

(Damn that was quick - now I have to completely re-write what I said, because what I said was not what I meant but I lost it in your save)

Is this a fair summary of your situation:

Is that what you're trying to say?

Sort of. Unit tests show that what you tested works in the environment in which you tested it. The system doesn't have to screw up necessarily. Extreme load, likely in good acceptance/unit tests, changes everything. I work in large distributed embedded systems where this is very true. Not so true in other areas.


I may be fighting city hall here, but you should ShipWithAssertionsOn (and discuss it there).


CategoryAssertions


EditText of this page (last edited April 29, 2006) or FindPage with title or text search