精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2006-11-16
public class MaintainRoleService extends ServiceSupport implements IMaintainRoleService{ private IRoleDAO roleDAO; public void setRoleDAO(IRoleDAO roleDAO) { this.roleDAO = roleDAO; } public void saveRole(RoleVO roleVO) throws BusinessException { if( roleVO == null || StringUtils.isBlank(roleVO.getId()) ){ throw new BusinessException(new Message("Arguments error")); } RoleVO returnedRoleVO = roleDAO.getByPk(roleVO.getId()); if( null != returnedRoleVO ){ throw new BusinessException( new Message("Inputed role number has existed in DB")); } if( null != roleVO.getParentRole() && !StringUtils.isBlank(roleVO.getParentRole().getId()) ){ RoleVO returnedParentRole = roleDAO.getByPk(roleVO.getParentRole().getId()); if ( returnedParentRole == null ){ throw new BusinessException( new Message("Unexpected error") ); } if( !RoleVO.ROLE_ST_VALID.equalsIgnoreCase(returnedParentRole.getStCd()) ){ throw new BusinessException( new Message( "Cannot add a sub role with a inactived parent role" ) ); } roleVO.setParentRole(returnedParentRole); } roleVO.setCreateDttm(DateUtil.getSystemTimestamp()); roleVO.setLastUpdDttm(DateUtil.getSystemTimestamp()); roleVO.setVersionNum(0); roleDAO.add(roleVO); } } 上面是一个经常可以见到的一个insert操作,因为这里的service方法依赖了DAO,也就是上面的IRoleDAO, 所以我在写testCase的时候就需要用mock来模拟roleDAO. 但是在我的service方法内部可能会调用好多次roleDAO方法。 比如我上面的saveRole方法就可能调用两次或者三次roleDAO方法, 其实上面Service方法也就决定了我不可能先写测试类,再去写实现类使测试通过! 因为我前面的测试数据,主要也就是对mock的expect的设置需要去了解service方法里面的逻辑才能知道,到底被测试的方法调用了多少次, 并且分别是调用了哪些DAO方法,到底我应该怎么样去设置mock的expect... 所以我感觉我要是这样写unit test 是不成功,不知道有没有朋友知道什么好的方法,或者给我点好的建议呢! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-11-16
引用 但是现在带来一个比较头痛的问题, 就是我必须去关注被测试对象的内部逻辑了,那这样的测试并不能叫做所谓了暗盒测试了 单元测试本来就是白盒测试啊! 当然你需要知道已知的输入参数下,应该会有如何的返回值,不然如何Mock? Mock只是让你不去关注方法的实现,但是并不代表你可以不关注这个方法的行为啊! |
|
返回顶楼 | |
发表时间:2006-11-16
Morgan0916 写道 引用 但是现在带来一个比较头痛的问题, 就是我必须去关注被测试对象的内部逻辑了,那这样的测试并不能叫做所谓了暗盒测试了 单元测试本来就是白盒测试啊! 当然你需要知道已知的输入参数下,应该会有如何的返回值,不然如何Mock? Mock只是让你不去关注方法的实现,但是并不代表你可以不关注这个方法的行为啊! 那也就是说, 如果用到了mock, 我也就没有办法去先写测试类再去写实现的具体类了?? 我的本意是测试类可以将被测试对象当作一个完全封闭的api来测试. 也就是从这个api的调用者去考虑! 本来是可以这样做的,不过现在加了mock后我就不可以这样做了...... 其实我们写的代码除了底层的 util 类, 有多少类是可以不用写mock直接测试的呀! 这样不就是永远也不可能达到从调用者去考虑写测试代码的境界了。 |
|
返回顶楼 | |
发表时间:2006-11-16
有没有朋友能帮我提供一个我上面代码中saveRole方法的测试呢!看看你们是怎么样去使用mock的呢!
|
|
返回顶楼 | |
发表时间:2006-11-16
你不知道调用多少次就不要在mock里边写明次数呗.那个次数是用来测试调用次数是否正确的.你还没有些实现,何必要测试那个依赖方法调用了多少次?可以等实现完毕后再补上这个测试用例.
|
|
返回顶楼 | |
发表时间:2006-11-16
我稍微写了一下测试类,请大家看看了! 不过我感觉这样的testCase很不稳定,太依赖被测试类了。如果被测试类做了些改动估计就要回头来改对应的testCase了。
public class MaintainRoleServiceTest extends TestCase { private MaintainRoleService maintainRoleService; private IRoleDAO roleDAOMock; protected void setUp() throws Exception { super.setUp(); maintainRoleService = new MaintainRoleService(); roleDAOMock = createMock(IRoleDAO.class); maintainRoleService.setRoleDAO(roleDAOMock); } protected void tearDown() throws Exception { super.tearDown(); //To change body of overridden methods use File | Settings | File Templates. } public void testSaveRole(){ //1. role have no parent role and passed all validation RoleVO roleVO = new RoleVO(); roleVO.setId("ROLE_USER");// Role Number roleVO.setRoleDesc("users"); // Role Description roleVO.setStCd(RoleVO.ROLE_ST_VALID); roleVO.setCreateUsrNum("DenisLing"); roleVO.setLastUpdUsrNum("DenisLing"); reset(roleDAOMock); expect(roleDAOMock.getByPk("ROLE_USER")).andReturn(null); expect(roleDAOMock.add(roleVO)).andReturn( "ROLE_USER"); replay(roleDAOMock); try{ maintainRoleService.saveRole(roleVO); }catch( BusinessException be ){ fail("Should not run here"); } verify(roleDAOMock); //2.role have no parent role but inputed role number has existed in db reset(roleDAOMock); expect(roleDAOMock.getByPk("ROLE_USER")).andReturn(roleVO); replay(roleDAOMock); try{ maintainRoleService.saveRole(roleVO); fail("should not run here");// }catch( BusinessException be ){ assertEquals("Inputed role number has existed in DB",be.getExceptionMessage().getMessageKey()); } //3. test the case with parent Role but parent role does not existed in DB RoleVO parentRoleVO = new RoleVO(); parentRoleVO.setId("ROLE_PARENT_USER"); roleVO.setParentRole(parentRoleVO); reset(roleDAOMock); expect( roleDAOMock.getByPk("ROLE_USER") ).andReturn(null); // no inputted role existed in DB expect( roleDAOMock.getByPk("ROLE_PARENT_USER") ).andReturn(null);// parent role doesn't exsited in DB replay(roleDAOMock); try{ maintainRoleService.saveRole(roleVO); fail();// should not run here }catch( BusinessException be ){ assertEquals("Unexpected error",be.getExceptionMessage().getMessageKey()); } verify(roleDAOMock); //4. test the case with parent Role but parent role's ST_CD is "S" suspend or "T" RoleVO returnedParentRoleVO = new RoleVO(); returnedParentRoleVO.setId("ROLE_PARENT_USER"); returnedParentRoleVO.setStCd("S"); reset(roleDAOMock); expect(roleDAOMock.getByPk("ROLE_USER")).andReturn(null); expect(roleDAOMock.getByPk("ROLE_PARENT_USER")).andReturn(returnedParentRoleVO); replay(roleDAOMock); try{ maintainRoleService.saveRole(roleVO); fail(); }catch(BusinessException be){ assertEquals("Cannot add a sub role with a inactived parent role",be.getExceptionMessage().getMessageKey()); } verify(roleDAOMock); returnedParentRoleVO.setStCd("T"); reset(roleDAOMock); expect(roleDAOMock.getByPk("ROLE_USER")).andReturn(null); expect(roleDAOMock.getByPk("ROLE_PARENT_USER")).andReturn(returnedParentRoleVO); replay(roleDAOMock); try{ maintainRoleService.saveRole(roleVO); fail(); }catch(BusinessException be){ assertEquals("Cannot add a sub role with a inactived parent role",be.getExceptionMessage().getMessageKey()); } verify(roleDAOMock); } } |
|
返回顶楼 | |
发表时间:2006-11-16
这个test方法也太长了吧
|
|
返回顶楼 | |
发表时间:2006-11-17
lingcm 写道 Morgan0916 写道 引用 但是现在带来一个比较头痛的问题, 就是我必须去关注被测试对象的内部逻辑了,那这样的测试并不能叫做所谓了暗盒测试了 单元测试本来就是白盒测试啊! 当然你需要知道已知的输入参数下,应该会有如何的返回值,不然如何Mock? Mock只是让你不去关注方法的实现,但是并不代表你可以不关注这个方法的行为啊! 那也就是说, 如果用到了mock, 我也就没有办法去先写测试类再去写实现的具体类了?? 我的本意是测试类可以将被测试对象当作一个完全封闭的api来测试. 也就是从这个api的调用者去考虑! 本来是可以这样做的,不过现在加了mock后我就不可以这样做了...... 其实我们写的代码除了底层的 util 类, 有多少类是可以不用写mock直接测试的呀! 这样不就是永远也不可能达到从调用者去考虑写测试代码的境界了。 现在就拿你的这个例子来说吧.比如你想测试MaintainRoleService,而MaintainRoleService又依赖IRoleDAO object,那么你就需要对IRoleDAO做Mock.但是你必须先要写一个IRoleDAO interface,你并不需要去写实现类!但是你必须要在Mock中设定IRoleDAO interface中每个method的正确的行为,已知的输入参数下,应该会有如何的返回值,不然如何断言? 比如你要Mock roleDAO.add(roleVO), 再add()的实现中,或许是许多的数据库操作,但是我们此时mock的时候不用去关心这些,我们要关心的是调用这个方法后,如果添加成功,返回什么? 添加失败,又返回什么?此时不就可以去mock它可能的这些情况吗? 你不用去看别人的实现代码,看看设计文档就可以知道啦 |
|
返回顶楼 | |
发表时间:2006-11-17
参考Martin Fowler的这篇文章:
http://www.martinfowler.com/articles/mocksArentStubs.html 区别就在于测试是基于状态的还是基于交互的。个人比较喜欢基于状态的,使用Mock也不喜欢做verify,拿来当stub用。 |
|
返回顶楼 | |
发表时间:2007-01-08
你的感觉是对的,mock的方式其实就是在测试类的实现过程,已经不仅仅是在测试接口了。
对于一个代码来说,如果你测试他的时候感觉非mock不可,不然就没什么可测的,其实他的设计就已经出问题了,一定是各个功能模块的耦合性太高了。 mock和stub的区别是很大的,简单的说:mock是在测试一个类的内部是否正确;stub是假设这个类的接口完全正常,用它去测试其他的类。 |
|
返回顶楼 | |