<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    grails學(xué)習(xí)(二)grails單元測試

    以前我在小公司,完成項目功能是終極目標(biāo)。開發(fā)人員很害怕需求變化,因為他們改怕了。那問題出在哪里呢?后來我仔細(xì)想想,是沒有做測試造成。那開發(fā)人員為什么如此害怕需求變化,我舉個例子,a服務(wù)給b服務(wù)和c服務(wù)調(diào)用,后來需求改變,導(dǎo)致a服務(wù)無法滿足b服務(wù),能完成自身的功能是天大的事,于是沒有和別人溝通把a服務(wù)直接改了。項目上線,突然有一天客戶打電話說你們網(wǎng)站這里出問題,那里出問題,以前都不會的啊。你們怎么弄的。于是根據(jù)頁面錯誤信息,開發(fā)人員很快找到錯誤根源,原來a服務(wù)改動,導(dǎo)致b服務(wù)不正常。而d,e,f服務(wù)依賴于b,那么導(dǎo)致d,e,f相關(guān)功能都出錯了。立馬動手改,改完上線,能知道的問題都沒了,哈哈,真高興,可是不能高興太早哇,也許還有潛在bug。

    軟件的bug是無法避免,但是我們可以盡量減少bug,不斷提升代碼質(zhì)量。剛我也說過,上述問題造成的原因是沒有做測試。測試包括很多了,單元測試、集成測試和功能測試等等。既然測試如此重要,每完成一個類都能進(jìn)行測試。

    以前也許你比較糾結(jié),沒有好的工具,現(xiàn)在java社區(qū)非常活躍,我們可以選擇的太多太多了:junit4,jmock,mockito,easymock,TestNg等等。如果你用過grails,那么你更清楚,此類快速開發(fā)框架已經(jīng)幫我們集成好了。使用起來非常簡單。所以今天我主要講述下grails的單元測試。

    假設(shè)需求:我們給每個用戶分配工作,每個人都要完成兩件事情,第一件事情:根據(jù)自己的用戶名返回歡迎信息;第二件事情:根據(jù)自己的地址返回國家地區(qū)。

    詳細(xì)設(shè)計

    用戶信息類:
    package com.test.domian

    class User {

        
    int id
        String name
        String address
        
        
    static constraints = {
        }
    }

    工作服務(wù)接口:
    package com.test.services

    class WorkService {

        
    /**
         * 根據(jù)用戶名返回歡迎字符
         * 
    @param userName
         * 
    @return
         
    */
        def processWorkOne(String userName) {
        }
        
        
    /**
         * 根據(jù)地址返回地區(qū)
         * 
    @param address
         * 
    @return
         
    */
        def processWorkTwo(String address){
        }
        
    }

    用戶工作服務(wù):
    package com.test.services

    import com.test.domian.User

    class UserService {

        def workService
        
        def doWork() {
            
            def userList 
    = User.list()
            userList.each {
                it.name 
    = workService.processWorkOne(it.name)
                it.address 
    = workService.processWorkTwo(it.address)
                
            }
        }
    }

    我們重點來看下測試類:
    package com.test.services

    import grails.test.*

    import com.test.domian.User

    class UserServiceTests extends GrailsUnitTestCase {
        
    protected void setUp() {
            
    super.setUp()
        }

        
    protected void tearDown() {
            
    super.tearDown()
        }

        
    void testDoWork() {
            
            
    //構(gòu)造數(shù)據(jù),類似于數(shù)據(jù)庫存在三條記錄
            def user1 = new User(id:1, name:"lucy", address:"hangzhou")
            def user2 
    = new User(id:2, name:"lily", address:"wenzhou")
            def user3 
    = new User(id:3, name:"lilei", address:"beijing")
            mockDomain User, [user1, user2, user3]
            
            
    //mock WorkService接口的processWorkOne方法和processWorkTwo方法
            def workControl = mockFor(WorkService)
            def userCount 
    = User.count()
            
    while(userCount-- > 0){
                workControl.demand.processWorkOne(
    1..1){String userName ->
                    
    return "hello world, " << userName
                }
                workControl.demand.processWorkTwo(
    1..1){String address ->
                    
    return "location in " << address
                }
            }
            def workService 
    = workControl.createMock()
            
            
    //把構(gòu)造好的workservice傳給userservice
            UserService userService = new UserService()
            userService.workService 
    = workService
            
            userService.doWork()
            
            def user4 
    = User.findById(1)
            assertEquals 
    "hello world, lucy", user4.name
            assertEquals 
    "location in hangzhou", user4.address
        }
    }

    以下著重來具體說明:
    1、mockDomain方法就是構(gòu)造數(shù)據(jù),包括domain類的動態(tài)方法都可以使用,比如:save(),list(),findby*()等。代碼中的User.count(); User.list();就是因為調(diào)用了mockDomain方法才可以正常使用。如果是集成測試的話,grails會幫我們構(gòu)造好,可以直接使用。但這里是單元測試,所以需要自己mock。

    2、mockFor方法就是給WorkService構(gòu)造一個對象,然后給
    workControl對象的demand代理創(chuàng)建兩個UserService中用的processWorkOne和processWorkTwo方法,代碼中用到了1..1,表示mock對象只能調(diào)用這個方法一次,為什么要循環(huán)三次設(shè)置processWorkOne和processWorkTwo方法呢?因為我們在UserService是對三個對象分別進(jìn)行調(diào)用處理這兩件事情。也許你會想,干嘛不直接把1..3(最少調(diào)用一次,最多調(diào)用三次)。是的,我最開始也是這么來處理,可是單元測試就是同不過。
    如果把
    UserService類中的
    workControl.demand.processWorkOne(1..1){String userName ->
          
    return "hello world, " << userName
     }

    改成
    workControl.demand.processWorkOne(1..3){String userName ->
          
    return "hello world, " << userName
     }

    然后把UserServiceTests類中的:
    userList.each {
                it.name 
    = workService.processWorkOne(it.name)
                it.address 
    = workService.processWorkTwo(it.address)
    }
    改成
    userList.each {
                it.name 
    = workService.processWorkOne(it.name)
               
    it.name = workService.processWorkOne(it.name)
                it.name = workService.processWorkOne(it.name)
                it.address = workService.processWorkTwo(it.address)
    }

    單元測試可以通過,但是改成這樣
    userList.each {
                it.name 
    = workService.processWorkOne(it.name)
               
    it.name = workService.processWorkOne(it.name)
                it.address = workService.processWorkTwo(it.address)
               
    it.name = workService.processWorkOne(it.name)
    }
    單元測試通不過。
    以上就是表明1..3的含義:這個方法要連續(xù)被調(diào)用至少一次,至多三次。
    但是有的人說我在UserService中就要這么寫
    userList.each {
                it.name 
    = workService.processWorkOne(it.name)
               
    it.name = workService.processWorkOne(it.name)
                it.address = workService.processWorkTwo(it.address)
               
    it.name = workService.processWorkOne(it.name)
    }
    那我要怎么改單元測試才能通過?
    我們把
    UserServiceTests的demand這段代碼
    workControl.demand.processWorkOne(1..1){String userName ->
         
    return "hello world, " << userName
    }
    workControl.demand.processWorkTwo(
    1..1){String address ->
          
    return "location in " << address
    }

    改成
    workControl.demand.processWorkOne(1..2){String userName ->
          
    return "hello world, " << userName
    }
    workControl.demand.processWorkTwo(
    1..1){String address ->
           
    return "location in " << address
     }

    workControl.demand.processWorkOne(1..1){String address ->
           
    return "location in " << address
     }
    這樣就通過了。
    以上就是說明構(gòu)造出來的函數(shù)只能按照構(gòu)造的順序調(diào)用。今天就是因為這個花了我好長時間啊,希望我理解是正確的。如有不對,請留言糾正。



    posted on 2011-05-13 21:40 yangpingyu 閱讀(1881) 評論(0)  編輯  收藏 所屬分類: grails


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    <2011年5月>
    24252627282930
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    導(dǎo)航

    統(tǒng)計

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    收藏夾

    linux

    產(chǎn)品交互

    分析,設(shè)計,架構(gòu)

    安全

    技術(shù)牛人

    數(shù)據(jù)庫

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久精品成人免费看| 1000部无遮挡拍拍拍免费视频观看| 特黄aa级毛片免费视频播放| 在线a毛片免费视频观看| 成年网在线观看免费观看网址| 青青草a免费线观a| 未满十八私人高清免费影院| 国产亚洲福利精品一区| 无码免费午夜福利片在线| 污污免费在线观看| 亚洲人成网站在线观看播放动漫| 久久99精品视免费看| 亚洲欧美国产欧美色欲| 亚洲国产一二三精品无码| 成人黄软件网18免费下载成人黄18免费视频 | 看一级毛片免费观看视频| 国产亚洲人成无码网在线观看| 日韩少妇内射免费播放| 亚洲精品mv在线观看| 亚洲裸男gv网站| 午夜性色一区二区三区免费不卡视频| 亚洲高清在线播放| 男人的天堂亚洲一区二区三区| 亚洲不卡视频在线观看| 亚洲成?Ⅴ人在线观看无码| 国产成人精品免费视| 一区二区三区在线免费 | 久久久久久亚洲精品不卡| 又黄又爽又成人免费视频| 三根一起会坏掉的好痛免费三级全黄的视频在线观看 | 91麻豆国产免费观看| 香港一级毛片免费看| 国产成人精品日本亚洲专一区| 黄页网站免费观看| 久久美女网站免费| 一区免费在线观看| 国产成人精品日本亚洲语音| 亚洲日韩中文字幕| 亚洲AV无码乱码国产麻豆| 亚洲精品一级无码中文字幕| 好吊妞在线成人免费|