About

Practice Exam: Unit Testing, TDD & Integration

Theory: How to Approach These

This practice exam follows the professor’s style for Lecture 8 (suggested time: 30 minutes). It is based on the extreme-testing chapter of Myers’ book, which uses a prime-number program with JUnit. Review these before attempting it:

The exam question. A class Prime has a method static boolean isPrime(int n). It returns true if n is a prime number, and false otherwise. Numbers less than 2 are not prime. The method will be developed with test-driven design (TDD) and JUnit 4. Later, isPrime will be called by a module Report, which is not written yet. State explicitly your assumption(s).


Practice Exam Solutions

Exercise Q1a

Using the TDD state diagram, name the states and transitions you go through when you write the first test assertFalse(Prime.isPrime(1)) and then make it pass.

Show solution ↓
Solution

Assumptions: JUnit 4; n is an int; numbers below 2 (including 0 and negative numbers) are not prime; at the start no test and no isPrime code exist.

FromTransition (trigger)To
startenter: nothing written yet, so no test failsGREEN [all tests pass]
GREENwrite a failing test: assertFalse(Prime.isPrime(1)) fails because isPrime does not exist yetRED [1+ tests fail]
REDfix the functional code: write isPrime returning false [0 tests fail]GREEN [all tests pass]

So the path is start → GREEN → RED → GREEN. The test fails at first not because it is wrong but because, in TDD, the test is written before the code.

Exercise Q1b

Write a JUnit 4 test class with at least five test cases for isPrime. Include boundary values.

Show solution ↓
Solution

The specification has one boundary, “numbers less than 2 are not prime”, so the boundary values are 1 (just below), 2 (on the boundary, the smallest prime) and 3 (just above). Further cases cover the other partitions: zero and negative numbers, an even composite, an odd prime, an odd composite, and the square of a prime (which catches a loop that stops one step too early).

import org.junit.Test;
import static org.junit.Assert.*;

public class PrimeTest {

    @Test public void oneIsNotPrime()        { assertFalse(Prime.isPrime(1)); }   // just below boundary
    @Test public void twoIsPrime()           { assertTrue(Prime.isPrime(2)); }    // on the boundary
    @Test public void threeIsPrime()         { assertTrue(Prime.isPrime(3)); }    // just above boundary
    @Test public void zeroIsNotPrime()       { assertFalse(Prime.isPrime(0)); }
    @Test public void negativeIsNotPrime()   { assertFalse(Prime.isPrime(-5)); }
    @Test public void fourIsNotPrime()       { assertFalse(Prime.isPrime(4)); }   // even composite
    @Test public void sevenIsPrime()         { assertTrue(Prime.isPrime(7)); }    // odd prime
    @Test public void nineIsNotPrime()       { assertFalse(Prime.isPrime(9)); }   // odd composite
    @Test public void twentyFiveIsNotPrime() { assertFalse(Prime.isPrime(25)); }  // square of a prime
}

Every test case states its expected result (true or false), and each test is independent: none relies on state left by another.

Exercise Q1c

Give the code that makes the first test pass using “fake it”. Then give the general code after triangulation.

Show solution ↓
Solution

Fake it. The only test so far expects false for 1, so the simplest code that passes is a hard-coded constant:

static boolean isPrime(int n) {
    return false;          // fake it: passes assertFalse(isPrime(1))
}

Triangulation. The next test, assertTrue(Prime.isPrime(2)), cannot be passed by a constant false, so we are back in RED. As more examples arrive (2 and 3 prime, 4 and 9 not prime), no fake can satisfy them all, and the code is generalized: a number of at least 2 is prime if no number from 2 up to its square root divides it.

static boolean isPrime(int n) {
    if (n < 2) return false;               // 1, 0 and negatives are not prime
    for (int i = 2; i <= n / i; i++) {     // same as i * i <= n, but cannot overflow
        if (n % i == 0) return false;      // found a divisor
    }
    return true;
}

Why up to the square root: if n=a×bn = a \times b with a≤ba \le b, then a≤na \le \sqrt{n}, so any composite number has a divisor no larger than its square root. The condition i <= n / i is equivalent to i2≤ni^2 \le n for positive integers, but unlike i * i <= n it never overflows for values of n close to the largest int.

Check against the tests:

  • n=1,0,−5n = 1, 0, -5: n < 2, so false ✓
  • n=2n = 2: loop condition 2≤2/2=12 \le 2/2 = 1 is false, loop skipped, true ✓; n=3n = 3: 2≤12 \le 1 false, true ✓
  • n=4n = 4: i=2i = 2, 2≤22 \le 2, 4 mod 2=04 \bmod 2 = 0, false ✓
  • n=7n = 7: i=2i = 2, 2≤32 \le 3, 7 mod 2=17 \bmod 2 = 1; i=3i = 3, 3≤23 \le 2 false, true ✓
  • n=9n = 9: i=2i = 2, remainder 1; i=3i = 3, 3≤33 \le 3, 9 mod 3=09 \bmod 3 = 0, false ✓
  • n=25n = 25: i=2,3,4i = 2, 3, 4 leave remainders; i=5i = 5, 5≤55 \le 5, 25 mod 5=025 \bmod 5 = 0, false ✓

All nine tests pass: GREEN.

Exercise Q1d

Classify each result as a failure or an error: (i) isPrime(7) returns false; (ii) a test stops with a NullPointerException thrown by a broken setUp method.

Show solution ↓
Solution
ResultTypeReason
(i) isPrime(7) returns falseFailureThe test ran normally and the actual result (false) differs from the expected result (true): the test found a bug.
(ii) NullPointerException from setUpErrorThe test could not run properly; it crashed for a reason not caused by the test case’s expected result.
Exercise Q1e

To test isPrime before Report exists, do you need a stub or a driver? Why? Which integration strategy is this?

Show solution ↓
Solution

A driver (here, the JUnit test class), because the missing module Report is the caller of isPrime: it sits above the unit. Something must take its place and call isPrime with test inputs, and a fake caller is a driver. (A stub would replace a module that isPrime calls, and isPrime calls nothing.)

Testing the lower module first and using drivers in place of the higher modules that are not written yet is bottom-up integration. When Report is written, it replaces the driver and the two are tested together.