An Inside-Out Approach
When writing Self-Checking Tests, inspect the state of the System Under Test (SUT) after it has been exercised to ensure it matches the expected state. If the SUT is stateful, this can be achieved through Procedural State Verification or Expected State Specification. Otherwise, Behavior Verification can be used to verify indirect outputs of the SUT as it is being exercised when the state does not change or there is no state to verify. To determine the best approach, we must ascertain whether the expected outcome is a change of state or if we need to examine what occurs while the SUT is being exercised.
State Verification is pretty simple when developing software from the inside out — building the innermost objects first, then proceeding outward, building objects above them. This is a common approach in Test-Driven Development and is referred to as the Chicago School, which takes an inside-out, state-based approach, promoting high cohesion, with a greater emphasis on design patterns — although YAGNI is a risk.
Often referred to as “the path of least resistance”, Procedural State Verification simply makes assertions against the SUT, comparing individual state values against expected values. Some possible risks may include Obscure Tests, if multiple assertions are used to specify the expected outcome (see Assertion Roulette), or Test Code Duplication, if the same assertions are used in many tests or many times within a single test method.
This approach to state verification compares one or more objects (populated with the expected attributes) to those objects returned by the SUT. The state of these objects can be easily compared using a single equality assertion statement, resulting in concise, readable tests. This works best when the specification (object) is an instance of the same class returned by the SUT. This is useful when there are numerous attributes that must be compared and/or numerous tests that need to compare them.