Let’s consider the below Game class in a guessing game where a random target is chosen by the system and the user guesses the target. The system returns an appropriate message based on whether the guess was higher, lower or equal to the random target.
package org.game;
public class Game {
private int target = (int) (Math.random() * 100);
public int guess(int guess) {
return target - guess;
}
}
No magic there. Now let’s look at the unit test for this class.
package org.game;
// imports hidden;
public class GameTest {
private Game game;
@Before
public void setUp() {
game = new Game();
}
@Test
public void testHigherGuess() {
int result = game.guess(55);
Assert.assertTrue(result < 0);
}
@Test
public void testLowerGuess() {
int result = game.guess(35);
Assert.assertTrue(result > 0);
}
@Test
public void testCorrectGuess() {
int result = game.guess(50);
Assert.assertTrue(result == 0);
}
}
As you might have guessed by now this wouldn’t work as the target is randomly generated. Now we have three options to handle this.
PowerMock is a mocking framework which extends several popular frameworks to allow mocking of static methods and more. In this post we’ll use PowerMocks’ extension for EasyMock. The general technique to mock static methods using PowerMock is outlined here.
This wouldn’t work for system classes like Math. To workaround this, we can
prepare the class using the static method for test rather than the class
containing the static method. Which means we’d be using
@PrepareForTest(Game.class)
instead of @PrepareForTest(Math.class)
in our
case. The completed unit test would look like this.
package org.game;
// imports hidden
@RunWith(PowerMockRunner.class)
@PrepareForTest(Game.class) // Preparing class under test.
public class GameTest {
private Game game;
@Before
public void setUp() {
// Mocking Math.random()
PowerMock.mockStatic(Math.class);
EasyMock.expect(Math.random()).andReturn(0.50).anyTimes();
PowerMock.replay(Math.class);
game = new Game();
}
@Test
public void testHigherGuess() {
int result = game.guess(55);
Assert.assertTrue(result < 0);
}
@Test
public void testLowerGuess() {
int result = game.guess(35);
Assert.assertTrue(result > 0);
}
@Test
public void testCorrectGuess() {
int result = game.guess(50);
Assert.assertTrue(result == 0);
}
}
Now PowerMock ensures that any call to Math.random()
would always return a
constant value within the Game
class when used for testing. Hence we can test
the guess()
method just as how any client code using the Game
class would.
All opinions are my own. Copyright 2005 Chandra Sekar S.