1

I want to do a JUnit test on the ForecastDisplay class below that has no return value. The way this class works is that the currentPressure=29.92f gets replaced by a new pressure assigned in the tester class. The display method compares the new and old pressures and prints the appropriate message to the console. As this is a void method, I don't know how to test it.

For example: if I assign a new currentPressure of 35 in the JUnit test, then the first message will print because 35>29.92. If anyone could suggest how to test this I would appreciate it because so far I can't do this without changing the display method to return a value, which is cheating as I shouldn't have to adapt the code to pass a JUnit test. Thanks

public class ForecastDisplay implements Observer, DisplayElement {
private float currentPressure = 29.92f;  
private float lastPressure;
private WeatherData weatherData;

public ForecastDisplay(WeatherData weatherData) {
    this.weatherData = weatherData;
    weatherData.registerObserver(this);
}

public void update(float temp, float humidity, float pressure) {
    lastPressure = currentPressure;
    currentPressure = pressure;

    display();
}

public void display() {
    System.out.print("Forecast Display: ");
    if (currentPressure > lastPressure) {
        System.out.println("Improving weather on the way!");
    } else if (currentPressure == lastPressure) {
        System.out.println("More of the same");
    } else if (currentPressure < lastPressure) {
        System.out.println("Watch out for cooler, rainy weather");
    }
}


} 
Raedwald
  • 46,613
  • 43
  • 151
  • 237
kellzer
  • 131
  • 1
  • 3
  • 18
  • Would it kill you to refactor `display()` into two methods, one that returns whatever should be displayed and the other one to display it? Makes it a helluva lot easier to unit test... – Anders R. Bystrup Feb 27 '14 at 12:05
  • Yeah in reality that would probably be the easiest thing but it's a part of an assignment that I have so I have to carry out the test on this code as is. Thanks for the reply thou! – kellzer Feb 27 '14 at 12:09
  • possible duplicate of [How to test void method with Junit testing tools?](http://stackoverflow.com/questions/1244541/how-to-test-void-method-with-junit-testing-tools) – Martin Schröder Feb 27 '14 at 14:09
  • possible duplicate of [JUnit test for System.out.println()](http://stackoverflow.com/questions/1119385/junit-test-for-system-out-println) – Raedwald Jul 05 '14 at 13:27

6 Answers6

2

As it stands, you would need a tool like PowerMock to mock System.out in order to determine what the method tried to print. How about breaking up the concerns of working out the message (which needs to be tested) and the concern of display.

public String determineMessage() {
    String msg = "Forecast Display: ";
    if (currentPressure > lastPressure) {
        msg += "Improving weather on the way!";
    } else if (currentPressure == lastPressure) {
        msg += "More of the same";
    } else if (currentPressure < lastPressure) {
        msg += "Watch out for cooler, rainy weather";
    return msg;
 }

public void display() {
    System.out.println(determineMessage());
}

This way unit testing can be done by setting various pressures on the class and asserting that the message is determined correctly.

StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • Thanks for all the answers. Think changing the methods like you suggest is the best way to proceed because anything else is beyond the scope of what's required for this assignment. Thanks – kellzer Feb 27 '14 at 12:26
  • You can just do a `System.setOut(yourOutStream)` and check the content yourself. See my answer bellow! – TA Nguyen Feb 27 '14 at 12:28
2

If you can't refactor the display() method as others have suggested (and I agree) as the best solution, you could intercept System.out and make your asserts on that:

@Test
public void testDisplay()
{
    final ByteArrayOutputStream out = new ByteArrayOutputStream( 256 );
    PrintStream ps = new PrintStream( out );
    System.setOut( ps );
    Forecast f = new Forecast(...);
    f.update( ... );

    assertThat( "Expected whatever" , out.toString() , equalTo( "..." ) );
}

Cheers,

Anders R. Bystrup
  • 15,729
  • 10
  • 59
  • 55
2

In Java you can do a System.setOut(yourOutStream) use that and do a @Before and @After to clean up by System.setOut(null)

private final ByteArrayOutputStream out = new ByteArrayOutputStream();
@Before
public void redirectOut() {
    System.setOut(new PrintStream(out));
}

@After
public void cleanUpOut() {
    System.setOut(null);
}

and then you can test it like:

@Test
public void shouldUpdatePresure() {
    update(101.5, 80.0, 25.2);
    assertEquals("somevaluehere", out.toString());
}
TA Nguyen
  • 453
  • 1
  • 3
  • 8
1

This could be a good example of a class to refactor - if possible, you may not have the scope to do so - to make it more testable. E.g. if your method returned a String you could test it better. So one option could be to create two methods:

  • generateDisplayString()
  • displayForecast(String displayMe)

Or, have displayForecast() call generateDisplayString() itself. There are a few models you could use that wil make your class more testable.

Brian
  • 6,391
  • 3
  • 33
  • 49
0

I would suggest you create gettters and setters for your private methods (if you're using Eclipse: right click your class and select source, create getters and setters and click "select all"). Then, you could just use these methods to see if your private variables have changed.

@Test
public void testUpdate1() {
    //create a new instance of ForecastDisplay, for example fcd
    ...
    fcd.update(29, 45, 35);
    assertEquals(fcd.getCurrentPressure, 35, 0);
}
pietv8x
  • 248
  • 1
  • 9
0

Even if you can't refactor display add a getter for current pressure and use it in your tests to determine that it is set correctly.

onesixtyfourth
  • 744
  • 9
  • 30