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 如何在测试下模拟方法调用的方法_Java_Unit Testing_Mocking_Mockito - Fatal编程技术网

Java 如何在测试下模拟方法调用的方法

Java 如何在测试下模拟方法调用的方法,java,unit-testing,mocking,mockito,Java,Unit Testing,Mocking,Mockito,我正在处理遗留代码,并希望增加它的测试覆盖率 我有一门课,像: public class MyStrategy implements SomeStrategy { TimeAndDateUtils timeAndDateUtils = new TimeAndDateUtils(); @Override public boolean shouldBeExtracted(Argument argument) { Date currentDate = tim

我正在处理遗留代码,并希望增加它的测试覆盖率

我有一门课,像:

public class MyStrategy implements SomeStrategy {

    TimeAndDateUtils timeAndDateUtils = new TimeAndDateUtils();

    @Override
    public boolean shouldBeExtracted(Argument argument) {
        Date currentDate = timeAndDateUtils.getCurrentDate();
        return currentDate.isBefore(argument.getDate());
    }

}
我想测试shouldBeExtracted方法,模拟调用
timeAndDateUtils.getCurrentDate()
,以便它返回一些固定值

所以我想做的是:

Date currentDate = %some fixed date%
TimeAndDateUtils timeAndDateUtils = Mockito.mock(TimeAndDateUtils.class);
Mockito.when(timeAndDateUtils.getCurrentDate()).thenReturn(currentDate);
Assert.assertTrue(myStrategy.shouldBeExtracted(argument))

如何强制MyStrategy类使用模拟对象而不是创建自己的对象?

您可以使用反射将模拟放入MyStrategy对象中。它看起来是这样的:

MyStrategy myStrategy = new MyStrategy(); // I don't know if you are using DI
MyStrategy.class.getDeclaredField("timeAndDateUtils").set(myStrategy, timeAndDateUtilsMock);

您可以使用反射将mock放入MyStrategy对象中。它看起来是这样的:

MyStrategy myStrategy = new MyStrategy(); // I don't know if you are using DI
MyStrategy.class.getDeclaredField("timeAndDateUtils").set(myStrategy, timeAndDateUtilsMock);

timeAndDateUtils
是在类本身中创建的,这使得测试访问变得困难。通过构造函数注入依赖项,以便可以创建模拟

public class MyStrategy implements SomeStrategy {

    TimeAndDateUtils timeAndDateUtils;

    public MyStrategy(TimeAndDateUtils timeAndDateUtils) {
        this.timeAndDateUtils = timeAndDateUtils;
    }

    @Override
    public boolean shouldBeExtracted(Argument argument) {
        Date currentDate = timeAndDateUtils.getCurrentDate();
        return currentDate.isBefore(argument.getDate());
    }

}
试验


timeAndDateUtils
是在类本身中创建的,这使得测试访问变得困难。通过构造函数注入依赖项,以便可以创建模拟

public class MyStrategy implements SomeStrategy {

    TimeAndDateUtils timeAndDateUtils;

    public MyStrategy(TimeAndDateUtils timeAndDateUtils) {
        this.timeAndDateUtils = timeAndDateUtils;
    }

    @Override
    public boolean shouldBeExtracted(Argument argument) {
        Date currentDate = timeAndDateUtils.getCurrentDate();
        return currentDate.isBefore(argument.getDate());
    }

}
试验


Mockito有一个很好的类用于重写类内的私有对象。它被称为白盒。它是这样工作的

MyStrategy myStrategy = new MyStrategy();
TimeAndDateUtils timeAndDateUtils = Mockito.mock(TimeAndDateUtils.class);
Whitebox.setInternalState(myStartegy, "timeAndDateUtils", timeAndDateUtilsMock);

这将更改您的模拟的TimeAndDateUtils

Mockito有一个很好的类用于重写类内的私有对象。它被称为白盒。它是这样工作的

MyStrategy myStrategy = new MyStrategy();
TimeAndDateUtils timeAndDateUtils = Mockito.mock(TimeAndDateUtils.class);
Whitebox.setInternalState(myStartegy, "timeAndDateUtils", timeAndDateUtilsMock);

这将更改模拟的TimeAndDateUtils

假设无法重写现有代码以使其更易于测试,这是注释的典型用例,允许将模拟或间谍字段自动注入测试对象

@RunWith(MockitoJUnitRunner.class)
public class MyStrategyTest {
    @Mock
    private TimeAndDateUtils timeAndDateUtils;

    @InjectMocks
    private MyStrategy myStrategy;

    @Test
    public void testShouldBeExtracted() {
        ...
        Mockito.when(timeAndDateUtils.getCurrentDate()).thenReturn(currentDate);
        Assert.assertTrue(myStrategy.shouldBeExtracted(argument));
    }
}

假设您无法重写现有代码以使其更易于测试,这是注释的典型用例,允许将模拟或间谍字段自动注入测试对象

@RunWith(MockitoJUnitRunner.class)
public class MyStrategyTest {
    @Mock
    private TimeAndDateUtils timeAndDateUtils;

    @InjectMocks
    private MyStrategy myStrategy;

    @Test
    public void testShouldBeExtracted() {
        ...
        Mockito.when(timeAndDateUtils.getCurrentDate()).thenReturn(currentDate);
        Assert.assertTrue(myStrategy.shouldBeExtracted(argument));
    }
}


这是一个旧的JavaSE应用程序,没有任何DIHello@Nicolas,我使用的是Mockito 1.9.x。我在其他项目中广泛使用InjectMock。甚至在询问堆栈溢出之前,我也在本例中尝试过它。由于某些原因,它不起作用,所以我想,这与这个项目中完全缺乏DI有关。但由于你的解释,它实际上应该是有效的。我再试试看。Thx,Iryna。我刚刚用Mockito
1.9.5
测试了完全相同的代码,它工作得很好。请确保用
@RunWith(MockitoJUnitRunner.class)
Hello@Nicolas在用@InjectMocks注释myStrategy之后,我不能再模拟方法调用了。然后我得到一条错误消息:
when()需要一个参数,必须是“模拟的方法调用”。
这是一个没有任何DIHello@Nicolas的旧Java SE应用程序,我使用的是Mockito 1.9.x。我在其他项目中广泛使用InjectMock。甚至在询问堆栈溢出之前,我也在本例中尝试过它。由于某些原因,它不起作用,所以我想,这与这个项目中完全缺乏DI有关。但由于你的解释,它实际上应该是有效的。我再试试看。Thx,Iryna。我刚刚用Mockito
1.9.5
测试了完全相同的代码,它工作得很好。请确保用
@RunWith(MockitoJUnitRunner.class)
Hello@Nicolas在用@InjectMocks注释myStrategy之后,我不能再模拟方法调用了。然后我得到一条错误消息:
when()需要一个参数,该参数必须是“模拟的方法调用”。
该类是公共接口“SomeStrategy”的实现之一。我不喜欢只为其中一个更改构造函数。该类是公共接口“SomeStrategy”的实现之一。我不喜欢只为其中一个更改构造函数。这使得代码的可读性更差。谢谢你的建议!我发现@kimi82的解决方案更优雅了一点。谢谢你的建议!我发现@kimi82的解决方案更优雅了一点。虽然这会起作用,但这是一个糟糕的解决方案。相反,要测试的方法可以很容易地通过两个简单的测试来覆盖,传递一个
参数
,该参数包含当前日期之前/之后的日期。不需要模拟。这样做,您将在同一测试中测试2段遗留代码。除非TimeAndDateUtils是已知框架/库的一部分,否则我不会依赖TimeAndDateUtils类,我会为这两个类创建互不依赖的测试。十年的经验(以及创建的数千个测试)告诉我,集成测试总是比独立的单元测试更好。两者,TDD和BDD用于确保质量从未使用过BDD,只有TDD。(BDD要求在非技术利益相关者的直接参与下创建测试,这在实践中几乎是不可能实现的。)虽然这会起作用,但这是一个糟糕的解决方案。相反,要测试的方法可以很容易地通过两个简单的测试来覆盖,传递一个
参数
,该参数包含当前日期之前/之后的日期。不需要模拟。这样做,您将在同一测试中测试2段遗留代码。除非TimeAndDateUtils是已知框架/库的一部分,否则我不会依赖TimeAndDateUtils类,我会为这两个类创建互不依赖的测试。十年的经验(以及创建的数千个测试)告诉我,集成测试总是比独立的单元测试更好。两者,TDD和BDD用于确保质量从未使用过BDD,只有TDD。(BDD要求在非技术利益相关者的直接参与下创建测试,这在实践中几乎不可能实现。)