日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

大話重構(gòu)連載15:采用Mock技術(shù)完成測(cè)試

系統(tǒng) 1711 0
第五次重構(gòu)我們引入了數(shù)據(jù)庫(kù)的設(shè)計(jì),用戶信息要從數(shù)據(jù)庫(kù)中讀取,問(wèn)候語(yǔ)庫(kù)存儲(chǔ)在數(shù)據(jù)庫(kù)中,并支持添加與更新。數(shù)據(jù)庫(kù)的引入使自動(dòng)化測(cè)試變得困難了,因?yàn)閿?shù)據(jù)狀態(tài)總是變化著的,而這種變化使得測(cè)試過(guò)程不能復(fù)現(xiàn),這是我們不愿看到的。因此,我們?cè)谠O(shè)計(jì)時(shí)將業(yè)務(wù)與數(shù)據(jù)庫(kù)訪問(wèn)分離,形成了UserDao與GreetingRuleDao。此時(shí),我們的設(shè)計(jì)應(yīng)當(dāng)遵從“依賴反轉(zhuǎn)”原則,即將UserDao與GreetingRuleDao設(shè)計(jì)成接口,并編寫它們的實(shí)現(xiàn)UserDaoImpl與GreetingRuleDaoImpl。這樣設(shè)計(jì)就為我們Mock掉UserDao與GreetingRuleDao的實(shí)現(xiàn)類創(chuàng)造了條件。

這是我們的設(shè)計(jì):


圖4.3 HelloWorld的設(shè)計(jì)圖


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

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


這段測(cè)試程序比較長(zhǎng),但其它部分都是打醬油的,核心是那個(gè)testSayHelloInTheMorning()用例,即問(wèn)候早上好這個(gè)用例。userDao與greetingRuleDao是兩個(gè)接口,我們?cè)趯?shí)例化它們的時(shí)候,并沒(méi)有去創(chuàng)建它們的實(shí)現(xiàn)類,而是用Mock的方式進(jìn)行創(chuàng)建:

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


隨后我們開(kāi)始定義它們的行為loadUser()與getAllGreetingRules()。在這個(gè)測(cè)試用例中,我們并不關(guān)心它們是怎樣去數(shù)據(jù)庫(kù)里查詢數(shù)據(jù)并返回的,我們只關(guān)心它們是否得到應(yīng)該得到的參數(shù),并要求它們按照規(guī)定返回一個(gè)結(jié)果:

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



我們希望被測(cè)程序在執(zhí)行的時(shí)候調(diào)用了userDao.loadUser(userId),并且調(diào)用時(shí)傳入的參數(shù)userId = 2013090701。如果測(cè)試過(guò)程中傳入的參數(shù)是這個(gè)值,這一項(xiàng)檢查點(diǎn)可以通過(guò),否則不能通過(guò)。隨后我們希望該函數(shù)返回“鮑曉妹”這個(gè)用戶對(duì)象。通過(guò)Mock程序,我們完全將數(shù)據(jù)庫(kù)訪問(wèn)的過(guò)程剝離在自動(dòng)化測(cè)試之外,而只是驗(yàn)證它的輸入?yún)?shù),并指定測(cè)試所需的返回結(jié)果。也就是說(shuō)數(shù)據(jù)訪問(wèn)過(guò)程被Mock掉,而大大降低了測(cè)試難度。

如果UserDao與GreetingRuleDao的Mock程序不能得到規(guī)定的參數(shù)時(shí),測(cè)試就不能通過(guò),這就是說(shuō)傳遞給Mock程序的參數(shù)也成為了測(cè)試程序要驗(yàn)證的一個(gè)輸出。隨后,Mock程序返回規(guī)定值,該規(guī)定值則成為了被測(cè)程序的一個(gè)輸入。最后,被測(cè)程序根據(jù)這個(gè)輸入返回結(jié)果,為測(cè)試程序所驗(yàn)證,測(cè)試結(jié)束(如圖4.4所示)。


圖4.4 HelloWorld的自動(dòng)化測(cè)試


圖中的BUS層才是我們大量編碼,應(yīng)當(dāng)自動(dòng)化測(cè)試的部分。既然是測(cè)試就是驗(yàn)證怎樣的輸入,應(yīng)當(dāng)?shù)玫皆鯓拥妮敵觥eb層向BUS層發(fā)出的請(qǐng)求,即調(diào)用BUS層某個(gè)類的方法,就是測(cè)試用例中的一個(gè)輸入,執(zhí)行完該方法后的返回值就是測(cè)試用例的一個(gè)輸出。但是,這對(duì)輸入輸出并不是該測(cè)試用例的全部。這里經(jīng)過(guò)BUS層處理以后,經(jīng)過(guò)一系列的邏輯判斷和數(shù)據(jù)操作,隨后會(huì)去調(diào)用DAO層進(jìn)行數(shù)據(jù)訪問(wèn)操作。調(diào)用DAO層時(shí)所傳遞的參數(shù),就是測(cè)試用例的另一個(gè)輸出。圖中,從DAO層的輸入,到它的輸出,這段數(shù)據(jù)庫(kù)訪問(wèn)的過(guò)程被Mock程序Mock掉了,因?yàn)樗辉谶@個(gè)用例的測(cè)試范圍。然后DAO層返回給BUS層一個(gè)結(jié)果,該結(jié)果就是測(cè)試用例的另一個(gè)輸入。接著B(niǎo)US層會(huì)再次對(duì)這個(gè)返回結(jié)果進(jìn)行處理,最后返回給Web層最終的結(jié)果。這就是采用Mock方式進(jìn)行自動(dòng)化測(cè)試的一個(gè)完整流程。

采用自動(dòng)化測(cè)試,測(cè)試程序?qū)⒉辉衮?yàn)證后臺(tái)的數(shù)據(jù)庫(kù)是否正確,同時(shí)也不再驗(yàn)證前臺(tái)的Web應(yīng)用及其前端設(shè)備是否正確。在該例中,系統(tǒng)的真正目的是要在前臺(tái)顯示對(duì)用戶的問(wèn)候,因此將會(huì)有一個(gè)Action或Servlet調(diào)用HelloWorld:

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


然而,這些程序都不適合自動(dòng)化測(cè)試而應(yīng)采用手工測(cè)試。回顧HelloWorld自動(dòng)化測(cè)試建立的過(guò)程我們不難發(fā)現(xiàn),它在設(shè)計(jì)之初就實(shí)現(xiàn)了業(yè)務(wù)邏輯與Web應(yīng)用、與數(shù)據(jù)訪問(wèn)的分離,所以它可以輕易的建立自動(dòng)化測(cè)試。但是,不幸的是,我們大多數(shù)的遺留系統(tǒng)在設(shè)計(jì)之初都沒(méi)有考慮到這些。因此,我說(shuō),在重構(gòu)之初首先建立自動(dòng)化測(cè)試機(jī)制是不現(xiàn)實(shí)的,我們只能采用手工測(cè)試結(jié)合QTP的方式。只有當(dāng)我們通過(guò)重構(gòu),使系統(tǒng)架構(gòu)滿足自動(dòng)化測(cè)試的條件之后,自動(dòng)化測(cè)試才可以開(kāi)展。

毫無(wú)疑問(wèn),測(cè)試與重構(gòu)形成了一個(gè)“雞生蛋,還是蛋生雞”的怪圈,成為我們實(shí)踐系統(tǒng)重構(gòu)一大攔路虎。本書(shū)將在后面詳細(xì)討論這個(gè)話題(詳見(jiàn) 第十六章 測(cè)試的困境),為你破解這個(gè)謎團(tuán)。

大話重構(gòu)連載首頁(yè): http://fangang.iteye.com/blog/2081995
特別說(shuō)明:希望網(wǎng)友們?cè)谵D(zhuǎn)載本文時(shí),應(yīng)當(dāng)注明作者或出處,以示對(duì)作者的尊重,謝謝!

大話重構(gòu)連載15:采用Mock技術(shù)完成測(cè)試


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

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

【本文對(duì)您有幫助就好】

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

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 龙门县| 庄浪县| 策勒县| 宁晋县| 乳山市| 遂昌县| 武强县| 无极县| 佛坪县| 桐梓县| 德兴市| 司法| 武穴市| 广宗县| 衡南县| 花莲县| 蕲春县| 临高县| 武强县| 正蓝旗| 内乡县| 巴南区| 葵青区| 磴口县| 海阳市| 东莞市| 香格里拉县| 册亨县| 沧源| 绥德县| 石屏县| 璧山县| 祁东县| 友谊县| 牙克石市| 万盛区| 仪征市| 昭苏县| 聂荣县| 扎兰屯市| 万山特区|