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

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章