将mock对象注入实际实现的位置

时间:2015-08-04 10:50:29

标签: java junit mocking easymock inject

我想知道这段代码的含义:

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

1 个答案:

答案 0 :(得分:0)

MathApplication上的CalculatorService依赖,它提供 - 正如其名称所示 - 为计算提供服务。

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

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

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

最后你:

  1. 测试您的测试方法是否返回预期的结果 - assertXXX()
  2. 测试是否已使用calcService - verify()
  3. 顺便说一下,代码

    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
    

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