Permalink
Browse files

Refactoring Main to be more testable

Added tests for AgeGuesserUI as well.
  • Loading branch information...
dackerman committed May 3, 2016
1 parent df6a3ee commit 810bdd319077f18317c487fcb404ad6fba2594e6
@@ -0,0 +1,32 @@
package com.dacklabs.ageguesser;
public class AgeGuesserUI {
private final ConsoleIO io;
private final AgeGuesser guesser;
public AgeGuesserUI(ConsoleIO io, AgeGuesser guesser) {
this.io = io;
this.guesser = guesser;
}
public void start() {
io.printLine("I will guess your age, and you tell me if it was higher, lower, or yes.");
boolean correct = false;
while (!correct) {
int guess = guesser.guess();
io.printLine(String.format("Are you %d years old? (possible answers: higher, lower, yes)", guess));
String answer = io.getUserInput().toLowerCase();
if (answer.contains("higher")) {
guesser.addHint(HintDirection.HIGHER);
} else if (answer.contains("lower")) {
guesser.addHint(HintDirection.LOWER);
} else if (answer.contains("yes")) {
correct = true;
} else {
io.printLine(String.format("I didn't understand \"%s\". Try again", answer));
}
}
io.printLine(String.format("Hooray! I only needed %d hints!", guesser.hintsReceived()));
}
}
@@ -0,0 +1,7 @@
package com.dacklabs.ageguesser;
public interface ConsoleIO {
String getUserInput();
void printLine(String line);
}
@@ -1,32 +1,8 @@
package com.dacklabs.ageguesser;
import java.util.Scanner;
import static com.dacklabs.ageguesser.HintDirection.HIGHER;
import static com.dacklabs.ageguesser.HintDirection.LOWER;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("I will guess your age, and you tell me if it was higher, lower, or correct.");
AgeGuesser guesser = new AgeGuesser();
boolean correct = false;
while (!correct) {
int guess = guesser.guess();
System.out.println(String.format("Are you %d years old? (possible answers: higher, lower, correct)", guess));
String answer = scanner.nextLine().toLowerCase();
if (answer.contains("higher")) {
guesser.addHint(HIGHER);
} else if (answer.contains("lower")) {
guesser.addHint(LOWER);
} else if (answer.contains("correct")) {
correct = true;
} else {
System.out.println(String.format("I didn't understand \"%s\". Try again", answer));
}
}
System.out.println(String.format("Hooray! I only needed %d hints!", guesser.hintsReceived()));
AgeGuesserUI ui = new AgeGuesserUI(new SysIO(), new AgeGuesser());
ui.start();
}
}
@@ -0,0 +1,18 @@
package com.dacklabs.ageguesser;
import java.util.Scanner;
public final class SysIO implements ConsoleIO {
private final Scanner scanner = new Scanner(System.in);
@Override
public String getUserInput() {
return scanner.nextLine();
}
@Override
public void printLine(String line) {
System.out.println(line);
}
}
@@ -0,0 +1,66 @@
package com.dacklabs.ageguesser;
import org.junit.Test;
import static org.junit.Assert.*;
public class AgeGuesserUITest {
@Test
public void uiGuessesAgeAndCelebratesIfCorrect() {
FakeIO io = new FakeIO("yes");
AgeGuesser guesser = new AgeGuesser();
AgeGuesserUI ui = new AgeGuesserUI(io, guesser);
ui.start();
assertEquals(3, io.output.size());
String expectedFirstLine = "I will guess your age";
String expectedSecondLine = String.format("Are you %d years old? ", guesser.guess());
String expectedThirdLine = "Hooray! I only needed 0 hints";
assertTrue("first message wasn't instructions",
io.output.get(0).contains(expectedFirstLine));
assertTrue("second message doesn't contain the guess",
io.output.get(1).contains(expectedSecondLine));
assertTrue("third message doesn't contain a count of guesses",
io.output.get(2).contains(expectedThirdLine));
}
@Test
public void uiKeepsGuessingAgeUntilCorrect() {
FakeIO io = new FakeIO("higher", "lower", "yes");
AgeGuesserUI ui = new AgeGuesserUI(io, new AgeGuesser());
ui.start();
assertEquals(5, io.output.size());
String ageQuestionRegex = "Are you \\d+ years old.*";
assertTrue(io.output.get(1).matches(ageQuestionRegex));
assertTrue(io.output.get(2).matches(ageQuestionRegex));
assertTrue(io.output.get(3).matches(ageQuestionRegex));
}
@Test
public void uiTellsUserWhenItGetsAnInvalidCommandAndContinues() {
FakeIO io = new FakeIO("aljsfl;kasjdf", "yes");
AgeGuesserUI ui = new AgeGuesserUI(io, new AgeGuesser());
ui.start();
assertEquals(5, io.output.size());
String secondLine = io.output.get(2);
String expectedSecondLine = "I didn't understand \"aljsfl;kasjdf\"";
String lastLine = io.output.get(4);
assertTrue("Expected invalid command message but got " + secondLine, secondLine.contains(expectedSecondLine));
assertTrue("Expected Hooray but got " + lastLine, lastLine.contains("Hooray!"));
}
}
@@ -0,0 +1,30 @@
package com.dacklabs.ageguesser;
import java.util.ArrayList;
import java.util.List;
public class FakeIO implements ConsoleIO {
private int lineIndex = 0;
private final String[] lines;
// This is public so the test can inspect it easily
public final List<String> output = new ArrayList<>();
// lines are what will pretend to be coming from System.in
public FakeIO(String... lines) {
this.lines = lines;
}
@Override
public String getUserInput() {
// return the next line that was passed in
return lines[lineIndex++];
}
@Override
public void printLine(String line) {
// the SUT calls this, and we just record it for later inspection
output.add(line);
}
}

0 comments on commit 810bdd3

Please sign in to comment.