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:
TDD state diagram (see 8.4): two states, GREEN [all tests pass] and RED [1+ tests fail]; from start you enter GREEN; write a failing test takes you to RED; fix the functional code [0 tests fail] brings you back.
JUnit 4 (see 8.5): @Test methods, assertTrue / assertFalse / assertEquals, no need to extend TestCase.
Boundary values (see 5.3): for “numbers less than 2 are not prime”, test just below, at and just above the boundary (1, 2, 3).
Three ways to green (see 8.4): fake it, obvious implementation, triangulation.
Failure vs. error (see 8.1): wrong answer = failure; crash not caused by the expected result = error.
Stub or driver (see 8.2, 8.3): missing caller → driver (bottom-up); missing callee → stub (top-down).
State your assumptions before you answer.
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 ↓Hide 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.
From
Transition (trigger)
To
start
enter: nothing written yet, so no test fails
GREEN [all tests pass]
GREEN
write a failing test: assertFalse(Prime.isPrime(1)) fails because isPrime does not exist yet
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 ↓Hide 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 ↓Hide solution ↑
Solution
Fake it. The only test so far expects false for 1, so the simplest code that passes is a hard-coded constant:
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×b with a≤b, then a≤n, so any composite number has a divisor no larger than its square root. The condition i <= n / i is equivalent to i2≤n for positive integers, but unlike i * i <= n it never overflows for values of n close to the largest int.
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 ↓Hide solution ↑
Solution
Result
Type
Reason
(i) isPrime(7) returns false
Failure
The test ran normally and the actual result (false) differs from the expected result (true): the test found a bug.
(ii) NullPointerException from setUp
Error
The 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 ↓Hide 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.