Verification by Pattern

Just for linguistic diversity and because regular expressions are easier, let’s translate our example to Perl. To show that some of our techniques apply outside of an object-oriented context, let’s also make this procedural Perl (see Listing 7-4).

Listing 7-4: Listing 7-1 rewritten in Perl

package pattern;

sub describeAddition {
  my $left = shift;
  my $right = shift;
  my $sum = $left + $right;
  return "The sum of $left and $right is $sum";
}

Listing 7-5 shows how our original exact equality test might look like using Test::Unit, the Perl entry into the xUnit family.

Listing 7-5: Listing 7-2 rewritten in Perl using Test::Unit

use Test::Unit::Procedural;
use pattern;

sub test_describeAddition {
  my $left = 13;
  my $right = 17;
  my $expectedSum = $left + $right;

  $result = pattern::describeAddition($left, $right);

  assert($result eq
      "The sum of $left and $right is $expectedSum";
}

create_suite();
run_suite();

This test exhibits the same problems we noted before. We make hard-coded “assumptions” about the strings that join the numbers together. The test is not resilient to changes in the joining strings. How could we fix this in a nice, Perl-ish way?

One of Perl’s strongest suits is the ease with which you can use regular expressions. Let’s exploit that strength. First, we need to consider what we know about the expected result in a way that can be expressed as a regular expression, independent of the joining strings. Given the output that we know, we expect to have the first operand, the second operand, and the sum in that order and with some characters between them. Additionally, the sum is at the end of the result string. This lets us replace the assertion in the original test with

assert($result =~ /$left.*$right.*$expectedSum$/);

For those not familiar with the Perl regular expression operators, the =~ operator yields a Boolean result indicating whether the string on the left is matched by the regular expression on the right. We are asserting that $result matches the given regular expression.1

1. If you’re a little rusty on your regular expressions, the regular expression is normally delimited by the slash (/) character; the entire expression between the slashes is the regular expression to be matched. The expressions $left, $right, and $expectedSum are replaced with the values of our local variables in the test as literals in the regular expression. The dot (.) character means “any character.” The asterisk (*) says “zero or more occurrences of the preceding pattern.” Put them together and it expresses the “some characters between them” that we discussed. The last piece is the terminal dollar sign ($). Unlike the dollar signs that are used to denote variable references, the one at the end anchors the regular expression to the end of the string.

The net result is that we have verified that the values we expect occur in the expected relative order in the result string. This test is stronger than the containment from the previous section. We are now validating the presence of all three values in a manner that distinguishes them from each other with no chance of zeros, duplicate values, or accidentally nested substrings producing false positives. We might strengthen it a little more through the addition of whitespace, although we would add elements that are not necessarily an important aspect of the test.

However, we still have issues with the maintainability of the test. It may be less fragile in the face of changes in the joining strings, but changes in argument order will break it. We have solved the “accidental equality” issue, but still have an “accidental similarity” issue. What would happen if we changed the phrasing to “You get 8 when you add 3 and 5”? Or what would happen if we internationalized the code and executed our test in a locale in which the natural word order would change? By the end of this chapter, we will have a solution for these.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.136.142