简体   繁体   中英

Junit Test for method with random number

I'm trying to create a Junit test for a method which is using a simple random number for calling another simple method which returns rock, paper, or scissor depending on the value of the parameter.

I don't know how to do this.

public class Play {

    public String player2Choice() {

        // Create a Random object.
        Random random = new Random();

        // Ramdon number between 1-3
        int numberChoice = random.nextInt(3) + 1;

        // Return the player random choice
        return getItem(numberChoice);
    }

    public String getItem(int numberChoice) {

        String item;

        switch (numberChoice) {
        case 1:
            item = "rock";
            break;
        case 2:
            item = "scissors";
            break;
        case 3:
            item = "paper";
            break;
        default:
            item = null;
        }

        return item;
    }
}

Right now I have this test:

Play play;

@Before
public void setup() {

    play = new Play();
}

@Test
public void testPlayer2Choice() {

    int param = 1;
    Play play2 = Mockito.mock(Play.class);


    play2.getItem(param);
    Mockito.verify(play2).getItem(param);

    String result = play.player2Choice();

    assertEquals("rock", result);


}

Play is tightly coupled to Random , which it really has no control over. This makes testing specific number choices difficult.

If the goal is to test that given a number choice of 1 , player2Choice returns "rock" then more control of the so-called randomness is needed.

public interface RandomInteger {
    int nextInt(int max);
}

The implementation of the interface will encapsulate an actual Random class and proxy the desired behavior/functionality

public class RandomIntegerImplementation : RandomInteger {
    private Random random ;

    public RandomIntegerImplementation() {
        // Create a Random object.
        random  = new Random();
    }

    public int nextInt(int max) {
        return random.nextInt(max);
    }
}

Play would then need to be refactored to explicitly depend on the now abstraction random provider.

public class Play {
    private RandomInteger random;

    public Play(RandomInteger random) {
        this.random = random;
    }

    public String player2Choice() {
        // Ramdon number between 1-3
        int numberChoice = random.nextInt(3) + 1;

        // Return the player random choice
        return getItem(numberChoice);
    }

    //...code removed for brevity
}

So now if the above stated test case is to be satisfied, the dependency can be mocked to behave as expected.

RandomInteger random;

Play play;

@Before
public void setup() {
    random = Mockito.mock(RandomInteger.class);
    play = new Play(random);
}

@Test
public void testPlayer2Choice_Given_Zero() {
    //Arrange
    String expected = "rock";
    int numberChoice = 0;

    when(random.nextInt(3)).thenReturn(numberChoice);

    //Act
    String actual = play.player2Choice();

    //Assert
    Mockito.verify(play).getItem(numberChoice + 1);
    assertEquals(expected, actual);
}

This should be enough for a start. The same can be done for other test cases.

Eventually getItem could also be refactored out into its own service but that is outside of the scope of the original question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM