easymock教程-创建stub对象??? 前面教程中有个章节讨论到mock和stub的概念差别,一般来说easymock如其名所
easymock教程-创建stub对象
??? 前面教程中有个章节讨论到mock和stub的概念差别,一般来说easymock如其名所示,主要是用来做mock用的,但是easymock中也提供有对stub的支持, 主要体现在andStubAnswer(),andStubDelegateTo(),andStubReturn(),andStubThrow()和asStub()等方法的使用上。
?
??? 我们来看一个实际使用的例子:
?
????public?class?Business?{
????????private?Service?????service;
????????private?StubService?stubService;
????????public?void?execute1()?{
????????????if?(service.execute())?{
????????????????stubService.method1();
????????????}
????????}
????????public?void?execute2()?{
????????????if?(service.execute())?{
????????????????stubService.method2();
????????????}
????????}
????????public?void?execute3()?{
????????????if?(service.execute())?{
????????????????stubService.method1();
????????????????stubService.method2();
????????????}
????????}
????????public?void?setStubService(StubService?stubService)?{
????????????this.stubService?=?stubService;
????????}
????????public?void?setService(Service?service)?{
????????????this.service?=?service;
????????}
????}
????private?interface?Service?{
????????public?boolean?execute();
????}
????private?interface?StubService?{
????????public?String?method1();
????????public?String?method2();
????}
??? 这里的Business类依赖到Service和StubService,execute1() / execute2() / execute3() 是我们需要测试的三个方法,相同点都是必须调用service.execute(),不同点在于其后对stubService的调用各不相同。而我们假设在这里我们只关心Business类对Service的调用是否如预期,不关心对于StubService的调用,只要程序可以继续运行就可以了。
?
??? 一个正统的做法是手工写一个StubService的stub 实现,例如:
private?class?StubServiceImpl?{
?public?String?method1()?{
??return?"";
?}
?public?String?method2()?{
??return?"";
?}
}
??? 但是如果这个接口复杂方法众多,则这个stub类不得不实现所有的其他方法,即使完全用不到,因为java的语法限制。
?
??? 可以这样使用easymock来实现stub:
?
public?class?BusinessTest?{
????private?Business??????business;
????private?IMocksControl?mocksControl;
????private?Service???????service;
????@Before
????public?void?init()?{
????????business?=?new?Business();
????????business.setStubService(prepareStubService());
????????mocksControl?=?EasyMock.createStrictControl();
????????service?=?mocksControl.createMock("service",?Service.class);
????????business.setService(service);
????}
????private?StubService?prepareStubService()?{
????????StubService?service?=?EasyMock.createMock("stubService",?StubService.class);
????????service.method1();
????????EasyMock.expectLastCall().andStubReturn("");
????????service.method2();
????????EasyMock.expectLastCall().andStubReturn("");
????????EasyMock.replay(service);
????????return?service;
????}
????@Test
????public?void?testExecute1()?{
????????EasyMock.expect(service.execute()).andReturn(true);
????????mocksControl.replay();
????????business.execute1();
????????mocksControl.verify();
????}
????@Test
????public?void?testExecute2()?{
????????EasyMock.expect(service.execute()).andReturn(false);
????????mocksControl.replay();
????????business.execute2();
????????mocksControl.verify();
????}
????@Test
????public?void?testExecute3()?{
????????EasyMock.expect(service.execute()).andReturn(true);
????????mocksControl.replay();
????????business.execute3();
????????mocksControl.verify();
????}
}
?
??? 在方法prepareStubService()中,我们通过easymock创建了一个mock对象,然后和普通mock对象一样记录了期望的行为。不同的是用andStubReturn()替代了andReturn().
?
??? 然后我们直接调用EasyMock.replay(service),注意在这个测试案例中,我们另外创建了一个mocksControl并通过这个mocksControl创建了我们关注的Service接口的mock对象,它的record/replay/和verify()是和StubService完全分离的。这样做的好处是在execute1() / execute2() / execute3()的测试案例中,我们完全不必额外关心这个stub,所有的事情在init()函数中就已经准备好了。这样做的好处显而易见,execute1() / execute2() / execute3()的测试案例中,代码和测试逻辑都简单了。
?
??? 最后总结,在适当的时候使用easymock来创建stub对象,对于简化测试还是能有所帮助的。