Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用Mockito消除外部依赖?_Java_Unit Testing_Junit_Mocking_Mockito - Fatal编程技术网

Java 如何使用Mockito消除外部依赖?

Java 如何使用Mockito消除外部依赖?,java,unit-testing,junit,mocking,mockito,Java,Unit Testing,Junit,Mocking,Mockito,我在理解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 v

我在理解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的temp

Mockito测试是从testWeatherReport()运行的。这就是我被困的地方。执行此操作时,我可以模拟getHighTemp()返回90:

当(testMockito.getHighTemp())。然后返回(90)

但是,当从getForecast()调用时,我无法使其返回90。断言变得“冷”,因为它选择的是32,而不是90

Mockito背后的全部想法不是我可以模拟一个方法,并告诉它确切返回什么,以移除外部依赖吗?如果从getForecast()调用getHighTemp()不会返回90,我看不出Mockito的用途。我错过了什么?谢谢你的帮助和启发


Bill

在您的示例中,
testMockito
testJUnit
是不同的对象-您在
testMockito
上模拟了该方法,但是
testJUnit
实际实现了该方法,返回了32

你可能想考虑把代码稍微分解成两个类——然后你可以在GeHistBug()/<代码>中编写代码。在这里,您将提供模拟测试和实际运行代码的实际实现。(可能是某种原因)


以这种方式构建的代码似乎遵守了规则-例如,如果您需要更改天气数据供应商,这样做的好处是它会让您变得更容易。我认为,当你说“因为这是一个外部资源,我的Junit没有通过隔离测试”时,你无论如何都是沿着这些思路来的。

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

因此,在你的情况下:

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

谢谢@Sprinter。部分模拟对我来说很有效,而且使用非常简单。因为这个例子是为了我自己的Mockito培训,所以我对目前的结果感到满意。接下来,我将重构我的代码,看看还能从中学到什么。谢谢Matt。为了快速修复,我使用了@Sprinter描述的部分模拟。我还将尝试您的建议,并将该类分为两个类,以将模拟方法与真实方法分开。