【问题标题】:Inject the mock object where an actual implementation在实际实现的地方注入模拟对象
【发布时间】:2015-08-04 10:50:28
【问题描述】:

我想知道这段代码是什么意思:

mathApplication.setCalculatorService(calcService);

为什么要使用接口并从中创建对象?而这个注入是什么意思?

这是我的测试代码:

import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(EasyMockRunner.class)
public class MathApplicationTester {

    private MathApplication mathApplication;
    private CalculatorService calcService;

    @Before
    public void setUp() {
        mathApplication = new MathApplication();
        calcService = EasyMock.createMock(CalculatorService.class);
        mathApplication.setCalculatorService(calcService);
    }

    @Test
    public void testAddAndSubtract() {

        //add the behavior to add numbers
        EasyMock.expect(calcService.add(20.0, 10.0)).andReturn(30.0);

        //subtract the behavior to subtract numbers
        EasyMock.expect(calcService.subtract(20.0, 10.0)).andReturn(10.0);

        //activate the mock
        EasyMock.replay(calcService);

        //test the subtract functionality
        Assert.assertEquals(mathApplication.subtract(20.0, 10.0), 10.0, 0);

        //test the add functionality
        Assert.assertEquals(mathApplication.add(20.0, 10.0), 30.0, 0);

        //verify call to calcService is made or not
        EasyMock.verify(calcService);
    }
}

【问题讨论】:

标签: java junit mocking easymock inject


【解决方案1】:

MathApplication依赖依赖于CalculatorService,正如它的名字所暗示的那样,它提供了计算服务。

但是,在 单元测试 中,您只想测试被测类 (MathApplication),因此您想用 替换所有依赖项您自己的实现,您可以完全控制。为此,您使用模拟。

calcService = EasyMock.createMock(CalculatorService.class);

依赖注入是一种将您所依赖的对象“注入”到主对象中的模式。

有三种方法可以获取类所依赖的对象的实例。

public class MathApplication {
    // I need an instance of CalculatorService inside the code of MathApplication
    ...
}

1:在MathApplication 的代码中实例化对象(calculatorService 是本地属性还是类属性都没有关系)。这不是很推荐的方式。

public double subtract(double a, double b) {
    CalculatorService calculatorService = new SomeFastCalculatorService();
    return calculatorService.subtract(a, b);
}

2:将实例化任务委托给外部提供者,称为 factory

public double subtract(double a, double b) {
    CalculatorService calculatorService = CalculatorServiceFactory.getInstance();
    return calculatorService.subtract(a, b);
}

3:让外部人员通过提供注入点(通过构造函数或通过 setter 方法)来注入实例。

它通常用于构建整个应用程序的“依赖树”(通常使用诸如Spring Dependency InjectionJavaEE CDI 之类的框架)。这里它用来将你的模拟对象注入到被测类中:

mathApplication.setCalculatorService(calcService);

稍后,在您的 @Test 方法中,您可以准确设置模拟对象的行为。

EasyMock.expect(calcService.add(20.0, 10.0)).andReturn(30.0);

读作“当calcService.add() 用20 和10 调用时,给30”。

最后你:

  1. 测试您测试的方法是否返回预期的结果 - assertXXX()
  2. 测试是否使用了 calcService - verify()

顺便说一句,代码

Assert.assertEquals(mathApplication.subtract(20.0, 10.0), 10.0, 0);

包含错误 - 查看documentation。正确的应该是

Assert.assertEquals(10.0, mathApplication.subtract(20.0, 10.0), 0);

它的工作原理几乎相同,只是如果测试不起作用,您会收到更正确的错误消息:

Assertion error - expected 10.0, but was 11.0.

不管怎样,写成这样会更好读:

double expected = 30.0;
double actual = mathApplication.subtract(20.0, 10.0);
Assert.assertEquals(expected, actual, 0.0000000001); // never expect exact floating point result

以及为什么应该使用接口:这是一个很好的做法 :) 框架模拟接口比模拟类更容易(有些模拟框架甚至不能模拟一个类)。它还引导您学习将接口与其实现分离并编写更好的可测试类。

【讨论】:

  • 真的很有帮助的人。我知道代码是什么。我只是想不出注射部分出来了:\。我们为什么要这样做?
  • 现在你明白了吗? :) 顺便说一句,还请阅读有关 assert() 的正确用法。
  • 我在我的代码中读到了关于断言其他内容的信息。但是注射,noo :(你能帮我更多吗?
  • @Hamid 请查看我的回答中的两个链接:Spring Dependency Injection 和 JavaEE CDI。您还可以搜索依赖注入的更详细说明。我添加了更多解释,但您应该使用外部资源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-25
  • 2019-04-07
  • 2021-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多