kellzer
kellzer

Reputation: 131

How to unit test a method with no return value but which writes to System.out

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");
    }
}


} 

Upvotes: 1

Views: 7684

Answers (6)

onesixtyfourth
onesixtyfourth

Reputation: 866

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.

Upvotes: 0

Anders R. Bystrup
Anders R. Bystrup

Reputation: 16060

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,

Upvotes: 2

TA Nguyen
TA Nguyen

Reputation: 473

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());
}

Upvotes: 2

pietv8x
pietv8x

Reputation: 248

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);
}

Upvotes: 0

Brian
Brian

Reputation: 6450

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.

Upvotes: 1

StuartLC
StuartLC

Reputation: 107317

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.

Upvotes: 2

Related Questions