Introduction
An assertion tests the assumptions made in a program. It contains a Boolean expression that returns a true or false. If the statement is correct, it will return a true and the program will pass on the correct data to other processes in the program. If the statement is proven false, the assertion will notify the programmer by showing a system error in the program. Assertions help to detect bugs and errors made by the programmer, as well as help to reason the behavior of the program. It confirms the developer's assumption regarding the behavior of the program by throwing an error if the expression is false. A simple example of an assumption is a number that cannot hold a negative value. An assertion hence enables the developer to test his/her assumptions and quickly debug the program. Assertions are usually disabled as the program reaches the final stages of its developmental process. It is usually disabled in the final product to eliminate performance penalty entirely.
Reasons for Assertion
Discovering bugs at an early stage is good. All programs start with bugs, the debugging process is faster and simpler if the bugs are detected early. Detecting an error at compile time would be better than finding one in run-time. A run-time bug does not cause an immediate disaster. Instead, the consequences of the bug distort the execution and with the damaged program, it may corrupt files or consequences. Tracing the original cause can be a long and tedious process. Assertions provide a better way to detect and stop bugs as early as possible.
Enabling/Disabling Assertions
By default, assertions are disabled at runtime. Two command-line switches allow the user to selectively enable or disable assertions.
To enable assertions at various granularities, use the -enableassertions, or -ea, switch.
To disable assertions at various granularities, use the -disableassertions, or -da, switch.
You specify the granularity with the arguments that you provide to the switch:
* no arguments —> Enables or disables assertions in all classes except system classes.
* packageName… —> Enables or disables assertions in the named package and any subpackages.
* … —> Enables or disables assertions in the unnamed package in the current working directory.
* className —> Enables or disables assertions in the named class.
To enable assertions in all system classes, use a different switch: -enablesystemassertions, or -esa.
Similarly, to disable assertions in system classes, use -disablesystemassertions, or -dsa.
Types of assertions
There are some different types of assertions:
* A precondition assertions defines the conditions that must be met when a particular method is called.
* A post-condition assertions defines what a method does.
* An invariant assertions is defined as something that is known as a state-space consistency for a class.
* Data assertion defines the conditions that must exist at a particular location in the code.
Benefits of Assertions
* Reduced debugging time by pinpoint bugs at their source.
* Earlier bug detection by find bugs that have not yet propagated to an output.
* Increased observability by providing coverage statistics and insight into internal design events.
* Reduced coding and debugging time by specifying temporal behaviors more easily and concisely in a temporal language.
* Improved portability by travelling with the RTL code of the design.
* Increased reusability by executing in simulators and model checkers.
* Improved communication by removing ambiguities present in natural language (English) descriptions.
Examples
Internal Invariants
Before the introduction of assertions, several programmers used comments to indicate their assumptions concerning a program's behavior. For example:
if (i % 3 == 0) {
…
} else if (i % 3 == 1) {
…
} else { // We know (i % 3 == 2)
…
}
An assertion can now be used:
if (i % 3 == 0) {
…
} else if (i % 3 == 1) {
…
} else {
assert i % 3 == 2 : i;
…
}
Control-Flow Invariants
Placing an assertion at a location that you assume will not be reached.
The assertions statement to use is:
assert false;
For example, suppose you have a method that looks like this:
void trial() {
for (…) {
if (…)
return;
}
// Execution should never reach this point!!!
}
Replace the final comment so that the code now reads:
void trial() {
for (…) {
if (…)
return;
}
assert false; // Execution should never reach this point!
}
* assert i * assert ((i+3/2)>0):checkArgumentValue();
* assert quantity>0: “The stock quantity cannot be negative +” quantity;
* assert (!choice.equals(”));
Usage
* Assertion in design by contract
* Assertion for run-time checking
* Assertion during the development cycle
During the developement cycle, programmer would be able to use assertion to track for errors while excuting its program. This is because the enabling of assertion would prompt the programmer of errors while its being excuted. This allow programmers to easily locate these erros in the program.
* Static assertions
Assertion that are checked while compiling is known as static assertion.
Class Invariants
A class invariant is a predicate that must be true before and after any method completes. In the stack example, the invariant would be that the number of elements in the stack is greater than or equal to zero and the number of elements should not exceed the maximum capacity of the class.
Assertions during the development cycle
The programmer will typically run the program with assertions enabled, during the development cycle. When an assertion failure occurs, the programmer is immediately notified of the problem. Many assertion implementations will also halt the program's execution. This is useful, because, the program might corrupt its state and make the cause of the problem more difficult to locate, if continued to run after an assertion violation occurred. The programmer can usually fix the problem, using the information provided by the assertion failure. In this manner, debugging is simplified by assertions.
Assertions in design by contract
Assertions describe the state part of the code expects to find before it runs,i.e., it can be a form of documentation: (its preconditions). When they have finished running, assertions also determine the state the code expects to result in. Assertions can also determine invariants of a class. Such assertions are integrated into the language and are automatically extracted to document the class, forming an integral part of the method of design by contract. The advantage of using assertions rather than comments is that assertions can be checked every time the program is run; if the assertion no longer holds, an error can be reported. Hence, this approach is also useful in languages which do not explicitly support it. This prevents the code from getting out of sync with the assertions, which is a problem that takes place with comments.
Comparison with error handling
It is important to distinguish between assertions and routine error handling.
Assertions are used when a logically impossible situations exists and is used to discover programming errors. This is very different from error handling: In error handling, most error conditions are possible although some may not be likely to occur. Hence, assertions should not be used as a general-purpose error handling mechanism. They do not allow recovery from errors. This means that an assertion failure will halt the execution of a program abruptly.
Where not to use Assertions
* Assertions are not always applicable to all situations- a fact to remember is that when assertions are disabled, assertions cannot be used. Usually, assertion are used to check conditions during programming. Ideally, assertion is recommended to be turned of while developing and testing phase and turned on as the systems is running normally. This would enable the saving of memory.
* Assertions should not be used on public methods to check for arguments. Whether it is enabled or not, checking of arguments should be done by the method. Furthermore, wrong arguments to methods requires an appropriate IllegalArgumentException instead of a generic AssertionError to be thrown.
* Assertions should not be used to do any work when your application requires for correct operation. The reason for so is because assertions may be disabled and hence boolean expression contained in an assertion may not be evaluated. Take for instance in the case when assertions may be disabled, it would be wrong to do this “assert names.remove(null);” if suppose you wanted to remove all the null elements from a list names that contained one or more nulls. However, this will work if the asserts were enabled. So the correct way would be to perform the action before the assertion like this: “boolean nullsRemoved = names.remove(null); assert nullsRemoved;”.
Implementing Assertions in Java Technology
J2SE 1.3 and earlier versions have no built-in support for assertions. They can, however, be provided as an ad hoc solution. Here is an example of how you would roll your own assertion class.
Here we have an assert method that checks whether a Boolean expression is true or false. If the expression evaluates to true, then there is no effect. But if it evaluates to false, the assert method prints the stack trace and the program aborts. In this sample implementation, a second argument for a string is used so that the cause of error can be printed.
Note that in the assert method, I am checking whether the value of NDEBUG is on (true) or off (false). If NDEBUG sets to true, then the assertion is to be executed. Otherwise, it would have no effect. The user of this class is able to set assertions on or off by toggling the value of NDEBUG. Code Sample 1 shows my implementation.
Example
public class Assertion {
public static boolean NDEBUG = true;
private static void printStack(String why) { Throwable t = new Throwable(why); t.printStackTrace(); System.exit(1); }
public static void assert(boolean expression, String why) { if (NDEBUG && !expression) { printStack(why); } } }

