亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

大話重構連載15:采用Mock技術完成測試

系統 1779 0
第五次重構我們引入了數據庫的設計,用戶信息要從數據庫中讀取,問候語庫存儲在數據庫中,并支持添加與更新。數據庫的引入使自動化測試變得困難了,因為數據狀態總是變化著的,而這種變化使得測試過程不能復現,這是我們不愿看到的。因此,我們在設計時將業務與數據庫訪問分離,形成了UserDao與GreetingRuleDao。此時,我們的設計應當遵從“依賴反轉”原則,即將UserDao與GreetingRuleDao設計成接口,并編寫它們的實現UserDaoImpl與GreetingRuleDaoImpl。這樣設計就為我們Mock掉UserDao與GreetingRuleDao的實現類創造了條件。

這是我們的設計:


圖4.3 HelloWorld的設計圖


為此,我們編寫了這樣的測試程序:

    	private HelloWorld helloWorld = null;
	private GreetingToUserImpl greetingToUser = null;
	private GreetingAboutTimeImpl greetingAboutTime = null;
	private final static List<GreetingRule> GREETING_RULES = getRules();
	
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		helloWorld = new HelloWorld();
		greetingToUser = new GreetingToUserImpl();
		greetingAboutTime = new GreetingAboutTimeImpl();
		helloWorld.setGreetingToUser(greetingToUser);
		helloWorld.setGreetingAboutTime(greetingAboutTime);
	}
	
	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
		helloWorld = null;
		greetingToUser = null;
		greetingAboutTime = null;
	}

	/**
	 * Test method for {@link org...HelloWorld#sayHello(java.util.Date, java.lang.String)}.
	 */
	@Test
	public void testSayHelloInTheMorning() {
		final Date now = DateUtil.createDate(2013, 9, 7, 9, 23, 11);
		final long userId = 2013090701;
		
		UserDao userDao = createMock(UserDao.class);
		GreetingRuleDao greetingRuleDao = createMock(GreetingRuleDao.class);
		expect(userDao.loadUser(userId)).andAnswer(new IAnswer<User>(){
			@Override
			public User answer() throws Throwable {
				User user = new User();
				user.setUserId(userId);
				user.setName("鮑曉妹");
				return user;
			}});
		expect(greetingRuleDao.findAllGreetingRules())
		.andAnswer(new IAnswer<List<GreetingRule>>(){
			@Override
			public List<GreetingRule> answer() throws Throwable {
				return GREETING_RULES;
			}});
		replay(userDao);
		replay(greetingRuleDao);
		
		greetingToUser.setUserDao(userDao);
		greetingAboutTime.setGreetingRuleDao(greetingRuleDao);
		
		String result = helloWorld.sayHello(now, userId);
		Assert.assertEquals("Hi, 鮑曉妹. Good morning!", result);
		verify(userDao);
		verify(greetingRuleDao);
	}
  


這段測試程序比較長,但其它部分都是打醬油的,核心是那個testSayHelloInTheMorning()用例,即問候早上好這個用例。userDao與greetingRuleDao是兩個接口,我們在實例化它們的時候,并沒有去創建它們的實現類,而是用Mock的方式進行創建:

    	UserDao userDao = createMock(UserDao.class);
	GreetingRuleDao greetingRuleDao = createMock(GreetingRuleDao.class);
  


隨后我們開始定義它們的行為loadUser()與getAllGreetingRules()。在這個測試用例中,我們并不關心它們是怎樣去數據庫里查詢數據并返回的,我們只關心它們是否得到應該得到的參數,并要求它們按照規定返回一個結果:

    	final long userId = 2013090701;
	expect(userDao.loadUser(userId)).andAnswer(new IAnswer<User>(){
			@Override
			public User answer() throws Throwable {
				User user = new User();
				user.setUserId(userId);
				user.setName("鮑曉妹");
				return user;
			}});
  



我們希望被測程序在執行的時候調用了userDao.loadUser(userId),并且調用時傳入的參數userId = 2013090701。如果測試過程中傳入的參數是這個值,這一項檢查點可以通過,否則不能通過。隨后我們希望該函數返回“鮑曉妹”這個用戶對象。通過Mock程序,我們完全將數據庫訪問的過程剝離在自動化測試之外,而只是驗證它的輸入參數,并指定測試所需的返回結果。也就是說數據訪問過程被Mock掉,而大大降低了測試難度。

如果UserDao與GreetingRuleDao的Mock程序不能得到規定的參數時,測試就不能通過,這就是說傳遞給Mock程序的參數也成為了測試程序要驗證的一個輸出。隨后,Mock程序返回規定值,該規定值則成為了被測程序的一個輸入。最后,被測程序根據這個輸入返回結果,為測試程序所驗證,測試結束(如圖4.4所示)。


圖4.4 HelloWorld的自動化測試


圖中的BUS層才是我們大量編碼,應當自動化測試的部分。既然是測試就是驗證怎樣的輸入,應當得到怎樣的輸出。Web層向BUS層發出的請求,即調用BUS層某個類的方法,就是測試用例中的一個輸入,執行完該方法后的返回值就是測試用例的一個輸出。但是,這對輸入輸出并不是該測試用例的全部。這里經過BUS層處理以后,經過一系列的邏輯判斷和數據操作,隨后會去調用DAO層進行數據訪問操作。調用DAO層時所傳遞的參數,就是測試用例的另一個輸出。圖中,從DAO層的輸入,到它的輸出,這段數據庫訪問的過程被Mock程序Mock掉了,因為它不在這個用例的測試范圍。然后DAO層返回給BUS層一個結果,該結果就是測試用例的另一個輸入。接著BUS層會再次對這個返回結果進行處理,最后返回給Web層最終的結果。這就是采用Mock方式進行自動化測試的一個完整流程。

采用自動化測試,測試程序將不再驗證后臺的數據庫是否正確,同時也不再驗證前臺的Web應用及其前端設備是否正確。在該例中,系統的真正目的是要在前臺顯示對用戶的問候,因此將會有一個Action或Servlet調用HelloWorld:

    	Date now = DateUtil.getNow();
	String user = SessionUtil.getCurrentUser(session);
	HelloWorld helloWorld = new HelloWorld();
	String greeting = helloWorld.sayHello(now, user);
	request.setAttribute(“greeting”, greeting);
  


然而,這些程序都不適合自動化測試而應采用手工測試。回顧HelloWorld自動化測試建立的過程我們不難發現,它在設計之初就實現了業務邏輯與Web應用、與數據訪問的分離,所以它可以輕易的建立自動化測試。但是,不幸的是,我們大多數的遺留系統在設計之初都沒有考慮到這些。因此,我說,在重構之初首先建立自動化測試機制是不現實的,我們只能采用手工測試結合QTP的方式。只有當我們通過重構,使系統架構滿足自動化測試的條件之后,自動化測試才可以開展。

毫無疑問,測試與重構形成了一個“雞生蛋,還是蛋生雞”的怪圈,成為我們實踐系統重構一大攔路虎。本書將在后面詳細討論這個話題(詳見 第十六章 測試的困境),為你破解這個謎團。

大話重構連載首頁: http://fangang.iteye.com/blog/2081995
特別說明:希望網友們在轉載本文時,應當注明作者或出處,以示對作者的尊重,謝謝!

大話重構連載15:采用Mock技術完成測試


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久网页 | 色综合天天综合网国产成人 | 国产精品人成人免费国产 | 手机在线看片国产日韩生活片 | 久久天堂 | 国产色丁香久久综合 | 成人国产精品一区二区网站 | www.中文字幕.com | 久久午夜夜伦伦鲁鲁片 | 久久亚洲综合网 | 亚洲成a人伦理 | 精品一区二区久久 | 欧美精品18xxxhd4k | 国产高h| 日韩欧美国产高清在线观看 | 国产成人精品高清免费 | 日韩欧美网站 | 日韩字幕在线 | 精品一久久香蕉国产线看观 | 久久精品亚洲日本筱田优 | 欧美毛片aaaaa片久久久久 | 色综合久久精品中文字幕 | 香蕉精品视频在线观看入口 | 99久久精品免费看国产一区二区 | 欧美国产综合在线 | 国产成人精品18 | 国产精品成aⅴ人片在线观看 | 日本一级毛片视频网站 | 久久思 | 欧美精品日日鲁夜夜 | 寂寞午夜影院 | 成人在线观看不卡 | 亚洲国产精品激情在线观看 | 国语一级毛片 | 国产成人精品视频 | 麻豆久久婷婷综合五月国产 | 国产激情在线 | 天天操夜夜草 | 91精品国产综合久久福利 | 亚洲欧美综合乱码精品成人网 | 国内精品免费视频 |