Encapsulate Loop Conditions

Sometimes the termination condition of a loop is independent of the data being manipulated in the loop. One example occurs when you are looking for an external trigger such as an event, signal, or sensor reading to stop. Imagine you were writing the preheat controller for a commercial oven. Simplified pseudo-code for the initial heating cycle might look something like Listing 8-3.

Listing 8-3: Simple pseudo-code for externally triggered loop termination

while(underSetTemperature()) {
  keepHeating();
}

We have changed the problem domain slightly, but this example closely resembles the example from the previous section. The underSetTemperature() method encapsulates the logic around continuing to heat and returns a simple true or false. We can imagine that this method does something like reading a thermometer and comparing it to the set temperature to determine if more heat is needed.

Another common example frequently occurs in communication processing and in other types of processing that continue indefinitely or in which the termination condition is too complex for a simple conditional statement. In those cases, we have theoretically infinite loops (see Listing 8-4).

Listing 8-4: Pseudo-code for an “infinite” loop

void infiniteLoop() {
  while (true) {
    // Do something
    if (/* Some condition */) {
      break;
    }
  }
}

This form of loop can be particularly difficult to test. For one, it may be difficult to force it to terminate, leaving the possibility of an infinitely running test. If we are seeing strange behaviors that correspond to certain loop iterations, then the true condition inhibits our ability to control the iterations. If our code coverage requires us to execute zero, one, and many iterations of every loop, as you would have if you were using some coverage tools’ loop metrics, then it is impossible to execute the loop zero times.

In all of these circumstances, we can encapsulate the loop condition, even if it is a trivial encapsulation of return true, to give us fine-grained control over the loop for testing purposes as in Listing 8-5. The simple override for the zero execution coverage condition would return false instead of true. The more complex override to test, for example, the fifth iteration of the loop would count the number of times it was called and return false after five iterations.

Listing 8-5: Refactoring Listing 8-4 for testable loop control

boolean shouldContinueLoop() {
  return true;
}

void infiniteLoop() {
  while(shouldContinueLoop()) {
    // Do something
    if (/* Some condition */) {
      break;
    }
  }
}

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

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