jmockit------mock

刚进公司,写两个星期的单元测试。公司主要用Jmockit ,感觉用起来还不错,于是乎,把一些写单测的时候,常遇到的写法写了下来。

凡是单元测试,都需要做以下几件事情

1, 明确要测试的类,和方法

2, 明确测试的实现,需要哪些依赖

3, 针对这些外部依赖 进行 mock

4, 验证是否根据自己的输入取得自己的输出

那么在JMOCKIT中。

做到1 这点,使用@Tested这个 注解

做到2这点,使用@injected 这个注解

做到3这点,可以使用 Expectations 和 NonStrictExpectations

做到4这点,则可以使用junit 的Assert 或者 Verifications

那么常见的写法就贴个出来:

@Tested
	@Mocked(methods = "updateEditNum")
	private CustomerServiceImpl		customerServiceImpl;

	@Injectable
	private CustomerDao				customerDao;
	@Injectable
	private CustOptionalDao			custOptionalDao;
	@Injectable
	private CustAccountInfoDao		custAccountInfoDao;
	@Injectable
	private CustContactPhoneDao		custContactPhoneDao;
	@Injectable
	private CustContactDao			custContactDao;
	@Injectable
	private CustRecipDao			custRecipDao;
	@Injectable
	private CustAutoAuditInfoDao	custAutoAuditInfoDao;
 

	// 需要修改monogo数据
	@Test
	public void testUpdateCustomer_need_update_monogo() {

		CustomerVO customerVO = buildCustomer();
		nonstrictExpectations();
		customerServiceImpl.updateCustomer(customerVO);

		new Verifications() {
			{
				mongoUpdateService.modSaleData(anyLong, anyString);
				times = 1;
				mongoCoreWordFacade.modCoreWordData(anyLong, anyString, anyLong);
				times = 1;
			}

		};
	}
private void nonstrictExpectations() {
		new NonStrictExpectations() {
			{
				customerServiceImpl.updateEditNum((CustomerVO) any, (Map<String, Short>) any);
				result = null;

				customerDao.findById(anyLong);
				Customer customer = new Customer();
				customer.setFullName("unit test fullname change");
				customer.setStat1(StatMachineService.STAT1_IN_FOLLOWING_04);
				result = customer;
				custContactDao.saveOrUpdate((CustContact) any);
				CustContact c = new CustContact();
				c.setContactId(11l);
				result = c;
				custContactPhoneDao.saveOrUpdate((CustContactPhone) any);
				CustContactPhone p = new CustContactPhone();
				p.setPhoneId(22l);
				result = p;
			}
		};
	}

最常用的有了,但单元测试可不是那么简单。我这边碰到第一个情景是,测试一个service.doXXX() 。

但这个 doXXX()其实里面就调用了2个private方法,那么其实问题就转变成分别测试这两个private 方法:

主要使用的是:Deencapsulation

// 测试私有方法获取该类型的para数据字典 (不传 单位岗位ID)
	@Test
	public void testFindByTypeAndPosIdWithCache_NO_POS() {

		new NonStrictExpectations() {
			{
				paraDao.findByTypeAndPosid(ParaTypeEnum.auditAbandReason);
				List<Para> pararet = new ArrayList<Para>();
				Para p = new Para();
				p.setDelFlag((short) 0);
				p.setShare((short) 0);
				p.setName("这个客户不是火星来的么,所以不能审核通过的!");
				pararet.add(p);
				returns(pararet);
			}
		};

		List<Para> rets = Deencapsulation.invoke(paramServiceImpl, "findByTypeAndPosIdWithCache",
				ParaTypeEnum.auditAbandReason, new Long[] {});
		Assert.assertTrue(rets.get(0).getName().equals("这个客户不是火星来的么,所以不能审核通过的!"));

		new Verifications() {
			{
				calloutMemcachedClient.get(anyString);
				times = 1;
				calloutMemcachedClient.set(anyString, anyInt, anyString);
				times = 1;
			}
		};
	}
 

但是查看源码 发现 继承于 Invocations的 Expectations 和 Verifications 也都是有invoke 的反射方法已经提供好了。

第二种情况来了,我要测试的@Tested 类,里面本身也有需要mock 的方法,但只 mock 其中一个方法就够了

        @Tested
	@Mocked(methods = "updateEditNum")
	private CustomerServiceImpl		customerServiceImpl;
 

第三种情况来了,有个实现的地方需要mock ,但这个实现是这样的 A.doAA().doBB().doCC()

难道要先mock A.doAA(),然后在mock这个返回值的doBB() 。。。。 太麻烦了

来看下:

// 测试用户信息比较全,并且需要优先审核,会更新优先统计数
	@Test
	public void testAddCustomer(@Cascading final ServiceLocator ServiceLocator) {
		long custId = 38888888l;
		CustomerVO vo = new CustomerVO();
		vo.setFullName("单元测试用户");
		vo.setCustId(custId);
。。。。。
new NonStrictExpectations() {
			{
				ServiceLocator.getInstance().getBean("saleSetFacade");
				saleSetFacade = new SaleSetFacade() {

					public SaleSet findSaleSetById(Long id) {
						return null;
					}
。。。。。。
				};
				result = saleSetFacade;
			}
		};
 

猜你喜欢

转载自yjhexy.iteye.com/blog/1740443
今日推荐