在实际实现的地方注入模拟对象
Inject the mock object where an actual implementation
我想知道这段代码是什么意思:
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);
}
}
MathApplication
依赖 CalculatorService
,顾名思义,CalculatorService
提供计算服务。
然而,在单元测试中,你只想测试class被测(MathApplication
),所以你想将所有依赖项替换为你自己的实现,你可以完全控制它。为此,您使用模拟。
calcService = EasyMock.createMock(CalculatorService.class);
依赖注入是一种将你所依赖的对象"injects"注入主对象的模式。
可通过三种方法获取您 class 所依赖的对象的实例。
public class MathApplication {
// I need an instance of CalculatorService inside the code of MathApplication
...
}
1:在MathApplication
的代码中实例化对象(calculatorService
是本地的还是class的属性都没有关系)。这种方式不是很推荐。
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 方法。
它通常用于构建整个应用程序的 "dependency tree"(通常使用 Spring Dependency Injection or JavaEE CDI 等框架)。在这里,它用于将您的模拟对象注入到被测 class 中:
mathApplication.setCalculatorService(calcService);
稍后,在您的 @Test
方法中,您准确地设置了模拟对象的行为。
EasyMock.expect(calcService.add(20.0, 10.0)).andReturn(30.0);
读作 "when calcService.add()
is called with 20 and 10, give 30"。
最后你:
- 测试你的测试方法是否符合预期 returns -
assertXXX()
- 测试是否使用了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
为什么你应该接口:这是一个很好的做法:)框架模拟接口比 class 更容易(有些模拟框架甚至 cannot模拟 class)。它会引导您学习将接口与其实现分开并编写更好的可测试性 classes.
我想知道这段代码是什么意思:
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);
}
}
MathApplication
依赖 CalculatorService
,顾名思义,CalculatorService
提供计算服务。
然而,在单元测试中,你只想测试class被测(MathApplication
),所以你想将所有依赖项替换为你自己的实现,你可以完全控制它。为此,您使用模拟。
calcService = EasyMock.createMock(CalculatorService.class);
依赖注入是一种将你所依赖的对象"injects"注入主对象的模式。
可通过三种方法获取您 class 所依赖的对象的实例。
public class MathApplication {
// I need an instance of CalculatorService inside the code of MathApplication
...
}
1:在MathApplication
的代码中实例化对象(calculatorService
是本地的还是class的属性都没有关系)。这种方式不是很推荐。
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 方法。
它通常用于构建整个应用程序的 "dependency tree"(通常使用 Spring Dependency Injection or JavaEE CDI 等框架)。在这里,它用于将您的模拟对象注入到被测 class 中:
mathApplication.setCalculatorService(calcService);
稍后,在您的 @Test
方法中,您准确地设置了模拟对象的行为。
EasyMock.expect(calcService.add(20.0, 10.0)).andReturn(30.0);
读作 "when calcService.add()
is called with 20 and 10, give 30"。
最后你:
- 测试你的测试方法是否符合预期 returns -
assertXXX()
- 测试是否使用了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
为什么你应该接口:这是一个很好的做法:)框架模拟接口比 class 更容易(有些模拟框架甚至 cannot模拟 class)。它会引导您学习将接口与其实现分开并编写更好的可测试性 classes.