Ok, let's go into a bit of detail here...
The basic for a good unit test is good code. Which explains why writing unit tests doesn't only make code work more reliable, it also tends to make the coders write better code (because bad code if very often hard to test).
In your example you have two methods (I assume you aren't into the details of Object Oriented Programming (OOP) yet, so I will not go into how to structure your code even better with additional classes).
One method does the actual number crunching (ok, little bit crunching), the other does the input. Unfortunately, your input method is also your main method, so you could do that a little better, since main methods are not very good for testing.
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // We'll ignore finer problems with scanners, etc. here
playGame(scanner);
}
public static void playGame(Scanner scanner) {
System.out.println("Guess the number of Apples Tom has");
Scanner sc= new Scanner(System.in);
int number=sc.nextInt();
System.out.println("Tom, is it higher or lower?");
String higherOrLower=sc.nextLine();
while(true){
number= getValue(higherOrLower,number);
System.out.println("Tom, is it higher or lower?");
higherOrLower=sc.nextLine();
if(higherOrLower.equalsIgnoreCase("none")) {
break;
}
}
}
This little change will make your code much more testable. Let's start with the easy part, the getValue
method:
@Test
public void lower_should_return_number_minus_1() {
int result = getValue("lower", 10);
Assert.assertEquals(9, result); // simple assertions
}
@Test
public void higher_should_return_number_plus_1() {
int result = getValue("higher", 10);
Assert.assertEquals(11, result); // simple assertions
}
@Test
public void garbage_should_return_same_number() {
int result = getValue("Hello, Polly!", 10);
Assert.assertEquals(10, result); // simple assertions
}
This will test most of your possibilities. It would be a good idea to also test what happens if you enter null for a String, just to be sure ;-)
Testing the other method will be a little bit harder, since it involves a little tricking...
@Test(timeout=1000)
public void game_should_work_on_input() {
final ByteArrayInputStream stream = new ByteArrayInputStream(String.format("5%nlower%nlower%nnone%n").getBytes());
final Scanner scanner = new Scanner(stream);
playGame(scanner);
}
Here we simply create a "fake" input, that consists of "5", "lower", "lower" and "none" (honestly, there's a blank line between 5 and the first lower). The String.format
will add the correct new line char(s) for each %n
. If your test succeeds, it means the game was played to the end. If not, a timeout will happen auf 1000ms (which means your game did not end correctly, which it should). Didn't test it, honestly, but you can go from there, I'm sure. ;-)