Assertions and Exceptions
Assertions and exceptions testing is a
black-box unit
testing
technique for embedding tests
within classes.
What oracle do you use to know the expected behavior of an
object? The requirements of the application are at much too
high of a level of abstraction. A single requirement is
implemented by many collaborating classes, and a single class
collaborates with others to help implement many requirements.
The class comment is still at too high of a level of
abstraction, is potentially vague, and is typically not
testable. Even the class responsibilities are usually not
specific enough to be testable because they are implemented by
multiple methods. Class method signatures are even more
specific, but the operation name, parameter names, and
parameter types only give the blackbox interface and syntax of
the method, not its intended semantic meaning. Looking at the
method body only provides the “as coded” semantics,
which may include defects, but not the intended semantics.
The answer to these questions is given by:
- Assertions are Boolean expressions that define the
expected behavior of an object:
- Class invariants defined the valid states of a
class.
- Method preconditions define the conditions that must be
true prior to the execution of the associated method if the
method is to execute successfully.
- Method postconditions define the conditions that most
be true after the successful execution of the associated
method.
- Exceptions are special objects that report the occurrence
of error conditions.
The typical objectives of assertions and exceptions testing
are to:
- Provide an appropriate, testable oracle, defining the
expected behavior of a class.
- Define when exceptions should be raised (i.e., when
assertions are violated), so that classes containing
assertions are self-testing and significantly more robust
than classes that do not.
- Make classes more testable by making them more observable
(because assertions and exceptions bypass
encapsulation).
Assertions and exceptions testing can typically begin when
the following preconditions hold:
- The tester(s) has been trained in assertions and
exceptions testing.
- The interface and responsibilities of the software
component or class under test have been determined.
Assertions and exceptions testing is typically complete if
the following postconditions hold:
- For every public domain class:
- Every class invariant is coded.
- Every method precondition is coded.
- Every method postcondition is coded.
During assertions and exceptions testing, unit testers
typically perform the following steps:
- Determine and embed (into invariant methods) class
invariants based on the class’s:
- Name
- Definition as captured in the class comment.
- Responsibilities.
- Attributes.
- For each public and complex method (except for simple
getters and setters), determine and embed the associated
preconditions and postconditions based on the:
- Relevant class responsibilities.
- Method’s signature.
- Method’s implementation.
- For each assertion, determine and embed an associated
exception into the associated method.
- For each assertion / exception pair, develop a unit test
case to ensure that the exception is thrown if the assertion
is violated.
Assertions and exceptions testing typically results in the
following work products:
- Software components containing assertions and
exceptions.
Assertion and exception testing typically is subject to the
following limitations:
- It is often difficult to identify all relevant
assertions.
- Assertions are often difficult to determine and
code.
- Assertions do not provide robustness unless they
implemented in code.
- Do not leave assertions as comments; make them executable
code that throws exceptions.
- Do not include exceptions without a corresponding
assertion that is violated.