On this page:
2.1 Getting started
2.1.1 Adding the tester library to your project
2.1.2 Using the tester library to run your project
2.2 Using the tester library
2.2.1 Naming test methods
2.2.2 Writing test methods with multiple tests
2.2.3 Writing multiple test methods
2.2.4 The testing methods
2.2.4.1 Basic methods:
2.2.4.2 Exception testing
2.2.4.3 Testing methods with randomized results:
2.2.4.4 Collection-based methods:
2.2.4.5 Miscellaneous methods:
2.2.5 How check  Expect compares for equality
7.7

The Tester Library

Related files:
  tester.jar  

The tester library provides a mechanism for testing programs, checking that their results are as expected.

2.1 Getting started
2.1.1 Adding the tester library to your project

First download the tester library from the link above. Save it to your Eclipse workspace directory, or somewhere convenient to find. Then, for each Java project you create:

These instructions are for Eclipse; if you choose to use a different IDE, the details will be different but the main ideas are the same.

  1. Go to Project Properties (by right clicking on the project itself, in Eclipse’s Project Explorer view, or from the File menu).

  2. In the list on the left, select the Java Build Path, then select the Libraries tab.

  3. On the right click on Add External JARs...:

  4. The file chooser window will be shown. Navigate to where you saved the tester.jar file and select it.

  5. Hit Finish.

2.1.2 Using the tester library to run your project
  1. Make sure your project is highlighted in the Package Explorer pane.

  2. In the Run menu select Run Configurations.... Equivalently, you can use the dropdown menu from the Run toolbar button (which looks like a green "play" button):

  3. In the list on the left, make sure "Java Application" is selected. Then, in the top left corner of the inner pane click on the leftmost item. (When you mouse over it should show New launch configuration.)

  4. Choose a name for this configuration: usually you should choose the same as the name of your project, but you can make multiple run configurations, and so should give them different, memorable names.

  5. In the Main class: click on Search....

  6. Among Matching items select Main - tester and hit OK.

  7. Click on the tab (x)= Arguments. In the Program arguments text field enter the name of your examples class.

  8. At the bottom of the Run Configurations select Apply then Run.

  9. To run the configuration again, just click the "play" button on the toolbar.

2.2 Using the tester library
2.2.1 Naming test methods

The tester library expects a particular naming convention and signature for your test methods, or else it will not find them. Specifically, it is looking for:
  • Methods in the class whose name is specified in the run configuration,

  • whose name begins with the four letters test,

  • whose sole argument is a parameter of type Tester,

  • and whose return type is either boolean or void.

In other words, only the first of the signatures below will be run as a test case by the tester library:

class ExamplesTesting {
boolean testSomething(Tester t) { ... } // good!  
boolean tstTypos(Tester t) { ... } // wrong method name  
boolean dontTestThis(Tester t) { ... } // wrong method name  
boolean TestSomething(Tester t) // wrong method name  
boolean testSomething() { ... } // wrong signature  
boolean testSomething(Tester t, int anythingElse) { ... } // wrong signature  
int testSomething(Tester t) { ... } // wrong return type }
2.2.2 Writing test methods with multiple tests

Frequently, you will want to write multiple tests within a single test method. Your test methods will probably look something like this:

class ExamplesTesting {
boolean testNumbers(Tester t) {
return t.checkExpect(2 + 2, 4) // this should pass && t.checkExpect(9000, 70) // this should fail && t.checkExpect(4, 4) // this should pass && t.checkExpect(4, 5); // this should fail }
}

Be careful! When you run this test method, you will not see four tests! Instead, you will see only one test passing, and one test failing. As soon as one test fails, because the code is combining the results with logical-and (&&), and logical operators short-circuit, the subsequent tests will not be run. Don’t be fooled into thinking you only have "just one failing test", if that test is in the middle of a block of other test cases.

Two alternate approaches are to separate each test into its own test method, or to separate the tests into individual statements. If you have not yet seen how to do the latter, then stick to the style above and just be careful.

2.2.3 Writing multiple test methods

If you define multiple test methods in your examples class, e.g.
class ExamplesTesting {
boolean testScenario1(Tester t) {
return t.checkExpect(.......);
}
boolean testScenario2(Tester t) {
return t.checkExpect(.......);
}
boolean testScenario3(Tester t) {
return t.checkExpect(.......);
}
}

be aware that the tester library deliberately runs your tests in a random order every time. In other words, there is no guarantee that testScenario2 will run before testScenario3 or after testScenario1. This ensures that you’re not subtly relying on your tests running in a particular order relative to each other (especially when you rely on randomness or other mutable state) in order to pass. You need to ensure that your test cases are standalone, self-consistent, and can pass in whatever order they happen to run.

Within a single test method, tests will run in the sequence you wrote them in, like any Java method. The randomness described here is only at the level of independent test methods.

(This random-order behavior is standard across most testing frameworks, and is helpful for "keeping your code honest" about what is being tested.)

2.2.4 The testing methods

The tester library exposes the following methods:

2.2.4.1 Basic methods:
2.2.4.2 Exception testing
2.2.4.3 Testing methods with randomized results:

All the methods described above anticipate that the methods are deterministic. Sometimes, we need to test randomized methods instead, that might return one among several randomly chosen results.

2.2.4.4 Collection-based methods:
2.2.4.5 Miscellaneous methods:
2.2.5 How checkExpect compares for equality

The checkExpect test uses a sameValue algorithm, that considers two values the same when:
  • Both values are null

  • Both values are identically the same object (using ==)

  • When both values are Strings, and the equals method returns true

  • When both values are boxed versions of primitive values (i.e. Integer, Double, Boolean, etc.), and their contained primitive values are equal

  • When both values are WorldScenes or WorldImages (see The Image Library for more information), and the scenes or images are constructed in the same manner: i.e., using the same overlays, besides, etc. to construct the intended image. It does not compare the scenes in terms of their final rendered pixel output.

  • When both values are arrays, and they have the same lengths, and the same values at the same indices (using sameValue recursively)

  • When both values are java.util.Sets, and they are set-equal as described in checkSet: i.e., using the equals method on the set values and not sameValue.

  • When both values are java.lang.Iterables, and they are iterable-equal as described in checkIterable: i.e., using sameValue to compare the sequence of values in order from both inputs.

  • When both values are java.lang.Maps, in which case they must have the same size, the same keys (using the containsKey operation on the Map), and corresponding values must be the same (using sameValue).

  • For everything else (including all user-defined classes), both values must be instances of the same class, and their fields must have the same values as compared using sameValue.

The tester library can handle cycles in the data being compared, and will not get stuck in an infinite loop. (If there are cycles that pass through a Array, Set or Map, however, then the equals methods must not get stuck in an infinite loop. However, if you are using such data structures rather than implementing your own, you are responsible for using them correctly.)