我在掌握Mockito的概念时遇到了一些麻烦。我已经写了一个小程序来提供帮助,但是我无法让它做我想做的事。

这是我的代码:

// WeatherDemo.java:

package com.abc;

public class WeatherDemo {
    public String getForecast() {
        // Get the high remperature for today, and return back to the caller one of these values:
        // cold, mild, or hot
        // cold will be returned if the high temp is forecast to be less than 60.
        // hot will be returned if the high temp is forecast to be more than 79.
        // Otherwise, mild will be returned (this indicates a high temp in the 60s or 70s).
        int highTemp = getHighTemp();
        if (highTemp < 60)
            return("cold");
        if (highTemp > 79)
            return("hot");
        return("mild");
    }

    public int getHighTemp() {
        // Because this is a demo, we don't have access to any source (web service, DB, etc.) to get the high temp.
        // Just hard code a value here, but remember that if this were a real application, we would be dynamically
        //   retrieving the day's high temperature from some external source.
        int highTemp = 32;
        return(highTemp);
    }
}


================================================== =============================

// TestWeatherDemo.java:

package com.abc;

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.mockito.Mockito;

public class TestWeatherDemo {
    @Test
    public void testWeatherReport() {
        WeatherDemo testMockito = Mockito.mock(WeatherDemo.class);
        WeatherDemo testJUnit = new WeatherDemo();

        when(testMockito.getHighTemp()).thenReturn(90);
        assertEquals("hot", testJUnit.getForecast());
    }
}


================================================== =============================

基本上,我想在getForecast()上运行JUnit。根据当天的高温,它会返回冷,中或热。为了获得高温,它调用getHighTemp()。假设getHighTemp()调用Web服务获取温度(我仅出于测试目的对值进行了硬编码)。因为这是外部资源,所以Junit不能通过隔离测试,也根本不是单元测试。更不用说getHighTemp()不会在每次调用时都返回相同值的事实。

因此,我想模拟getHighTemp(),告诉它始终返回90的温度。

Mockito测试是从testWeatherReport()运行的。这就是我卡住的地方。这样做时,我可以模拟getHighTemp()返回90:

when(testMockito.getHighTemp())。thenReturn(90);

但是,当从getForecast()调用时,我无法使它返回90。断言之所以变得“冷”,是因为它选择了32个而非90。

Mockito背后的整个想法不是我可以模拟一个方法并确切告诉它要返回什么以删除外部依赖项吗?如果从getForecast()调用getHighTemp()不会返回90,则看不到Mockito的目的。我在这里想念什么?感谢您的帮助和启发。

法案

最佳答案

您本质上是在问“如何在测试其余类的同时模拟我的类中的一个方法”。可以使用Mockito-在文档中搜索“部分模拟”。但是,这(几乎)总是表明您的代码结构不良,需要进行重构。如果要测试访问要模拟的接口的类,则表明您应将该接口声明为interface,然后将实现传递给该类。这有两个效果:首先,它使您可以在不更改接口的情况下更改实现;其次,它使类可测试。

因此,在您的情况下:

public interface TempSupplier {
    int getHighTemp();
    int getLowTemp();
}

public class WeatherDescriber {
    private final TempSupplier tempSupplier;

    public WeatherDescriber(TempSupplier tempSupplier) {
        this.tempSupplier = tempSupplier;
    }

    public String getForecast() {
        int highTemp = tempSupplier.getHighTemp();
        ...
    }
}

@Test
public void testForecast() {
    TempSupplier supplier = mock(TempSupplier.class);
    when(supplier.getHighTemp()).thenReturn(90);
    WeatherDescriber describer = new WeatherDescriber(supplier);
    assertThat(describer.getForecast(), is("Hot"));
}


我通常将模拟分解为单独的方法,以便您可以轻松进行测试:

private WeatherDescriber getDescriber(int lowTemp, int highTemp) {
    TempSupplier supplier = mock(TempSupplier.class);
    when(supplier.getLowTemp()).thenReturn(lowTemp);
    when(supplier.getHighTemp()).thenReturn(highTemp);
    return new WeatherDescriber(supplier);
}

@Test
public void testDescribeVariousTemps() {
    assertThat(getDescriber(10, 20).getForecast(), is("cold"));
    assertThat(getDescriber(30, 35).getForecast(), is("cold"));
    assertThat(getDescriber(40, 45).getForecast(), is("warmer"));
    assertThat(getDescriber(90, 130).getForecast(), is("melting"));
}

08-05 17:52