Test First

Wait a minute. All we've done so far is write out comments describing what the class GameofWar needs to be able to do. We haven't even implemented the class--how can we test it? Well, we do know how the game is supposed to behave; that's what our problem statement tells us. For instance, we know that if the two played cards are equal in value, a war should occur. One of the first tests might be to check and make sure that really happens. Another might be to see if cards are transfered properly when someone wins a trick.

We won't actually run our tests until there is some code in the GameOfWar class. But we will do it very early. Let's say there's a method inside class GameOfWar that actually makes the war happen once two equal cards have been detected. Before we finish the implementation for that method, we will put a System.out.println in there just to tell us that the method has been called. All of our methods will announce themselves by console messages until we have them fleshed out. So we can still test that they are being called when they ought to be, even before we know if they do their designated task correctly.

You might be thinking of testing as simply using the program and seeing if it does what you expect it to do as you pretend to be the user. That is important, of course, and you do detect bugs that way. But we want to make testing more formal than that. This is especially important in a situation where randomness is involved, because as testers, we don't want to leave it up to chance to see special circumstances arise. Instead we should deliberately construct those special circumstances and then see if the program responds appropriately.

In computer science, the idea of a black box is something that does a task, but you don't know how it does that task. You are aware of the interface, but not the implementation. So, I know how to put a disc into my CD player (interface) but I don't know how the CD player actually turns that disc into music (implementation). Doing a black box test of my CD player might consist of inserting the disc and seeing if music comes out.

Black box testing really comes straight from the problem statement of coding project. Our game of War problem statement says that the game of War ends when someone runs out of cards. So, a good example of a black box test would be checking to see if our game of War really does that. That can take forever if all we do is just play the game. We need to rig a deck so that we know in advance exactly when the game should end, and then see if it really does.

In general, our tests should consist of situations where we know what the "answer" is and then we see if the program comes up with that. Suppose someone else writes a class called Averager that was designed to average some integers. You are assigned to write a black box test for the class. You don't know how the person computed the average (that's the implementation). You just know the interface of the class, namely what fields and methods it has. That's the information you find in the API Specification when you look up any class: a list of its fields and methods. So here is a method we find in class Averager:


average

public int average(int a, int b)
Returns the arithmetic mean of two integers.

Observing that method signature, you could then test that method like this:

void testAverage(){

Averager theAverager = new Averager();

if (theAverager.average(14, 20) == 17){

System.out.println("average test passed");

numPasses++;

}else{

System.out.println("average test failed");

numFailures++;

}

}

You might also try to think about some special circumstances, like if the two numbers are equal or if one is zero or negative, or something like that. Then you would write a test for each special circumstance and see if you get the correct behavior. The expected behavior is coded into the test, so the program output should simply report whether the test passed or failed.

Create a new class called TestGameOfWar. In comment form, write out the black box tests that will be sent to the class GameOfWar to ensure that it really is following the rules of the game. Try to think of some special circumstances, like if a player runs out of cards during a war. Assume that you can create a deck of cards with any size or composition you like. Probably most of the tests will be run with very small decks. If you are rigging a deck for your test, you should say exactly which cards will be in the rigged deck. We will later change that into code.

The demands of the testing program will actually shape the way the code gets written. We can see that already by thinking about our need to rig a deck. We certainly don't want our rigged deck to get shuffled. So the call to deck.shuffle() must be contained inside a method that we can bypass while still requesting for a game to be conducted. We also see that there needs to be a class constructor for our deck of cards class that allows for the possibility of non-standard decks. This is why it is important to design the black box tests in advance of writing the code for the black box. It's expensive to go back and change implementation later, once you realize what the tests will require.

As we work on implementing our game of War, we will constantly run the black box tests each time we change the program. If a bug gets introduced, we'll know exactly when it happened. Once we have some detailed code, we will then start analyzing the code itself and generate some additional things to test for. This is "white box" testing, because it means that we do know how the implementation works. For example, if we see a "while" loop somewhere in the code, we have to know what will happen if the boolean is false and the while loop never runs. Will something else be messed up further down? We should deliberately construct a circumstance where that loop never runs. We should also think about ways to convince ourselves that there is no way for the code to get trapped in an infinite loop at that point. Again, sending in special circumstances can help us check for that.

Read more about testing here.


Previous Topic Course Home Page Next Topic