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

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

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

    莊周夢(mèng)蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    Clojure世界:?jiǎn)卧獪y(cè)試

    Posted on 2012-02-15 19:39 dennis 閱讀(5062) 評(píng)論(0)  編輯  收藏 所屬分類: Clojure
        單元測(cè)試也是一個(gè)開發(fā)中最常見的需求,在Java里我們用JUnit或者TestNG,在clojure里也內(nèi)置了單元測(cè)試的庫。標(biāo)準(zhǔn)庫的clojure.test,以及第三方框架midje。這里我將主要介紹clojure.test這個(gè)標(biāo)準(zhǔn)庫,midje是個(gè)更加強(qiáng)大的測(cè)試框架,廣告下,midje的介紹在第二次cn-clojure聚會(huì)上將有個(gè)Topic,我就不畫蛇添足了。通常來說,clojure.test足夠讓你對(duì)付日常的測(cè)試。

        首先看一個(gè)最簡(jiǎn)單的例子,定義一個(gè)函數(shù)square來計(jì)算平方,然后我們測(cè)試這個(gè)函數(shù):
    ;;引用clojure.test
    (ns example
      (:use [clojure.test :only [deftest 
    is run-tests]]))
    ;;定義函數(shù)
    (defn square [x]
      (
    * x x))
    ;;測(cè)試函數(shù)
    (deftest test
    -square
      (
    is (= 4 (square 2)))
      (
    is (= 9 (square -3))))
    ;;運(yùn)行測(cè)試
    (run
    -tests 'example)

        執(zhí)行輸出:

    Testing example

    Ran 
    1 tests containing 2 assertions.
    0 failures, 0 errors.

        這個(gè)小例子基本說明了clojure.test的主要功能。首先是斷言is,類似JUnit里的assertTrue,用來判斷form是否為true,它還可以接受一個(gè)額外的msg參數(shù)來描述斷言:
     (is (= 4 (square 2)) "a test")
        它還有兩種變形,專門用來判斷測(cè)試是否拋出異常:
     (is (thrown? RuntimeException (square "a")))
     (
    is (thrown-with-msg? RuntimeException #"java.lang.String cannot be cast to java.lang.Number"  (square "a")))
        上面的例子故意求"a"的平方,這會(huì)拋出一個(gè)java.lang.ClassCastException,一個(gè)運(yùn)行時(shí)異常,并且異常信息為java.lang.String cannot be cast to java.lang.Number。我們可以通過上面的方式來測(cè)試這種意外情況。clojure.test還提供了另一個(gè)斷言are,用來判斷多個(gè)form:
     (testing "test zero or one"
        (are
         (
    = 0 (square 0))
         (
    = 1 (square 1))))
        are接受多個(gè)form并判斷是否正確。這里還用了testing這個(gè)宏來添加一段字符串來描述測(cè)試的內(nèi)容。

        其次,我們用deftest宏定義了一個(gè)測(cè)試用例,deftest定義的測(cè)試用例也可以組合起來:
       (deftest addition
         (
    is (= 4 (+ 2 2)))
         (
    is (= 7 (+ 3 4))))
       (deftest subtraction
         (
    is (= 1 (- 4 3)))
         (
    is (= 3 (- 7 4))))
       (deftest arithmetic
         (addition)
         (subtraction))

        但是組合后的tests運(yùn)行就不能簡(jiǎn)單地傳入一個(gè)ns,而需要定義一個(gè)test-ns-hook指定要跑的測(cè)試用例,否則組合的用例如上面的addition和subtraction會(huì)運(yùn)行兩次。我們馬上談到。

        定義完用例后是運(yùn)行測(cè)試,運(yùn)行測(cè)試使用run-tests,可以指定要跑測(cè)試的ns,run-tests接受可變參數(shù)個(gè)的ns。剛才提到,組合tests的時(shí)候會(huì)有重復(fù)運(yùn)行的問題,要防止重復(fù)運(yùn)行,可以定義一個(gè)test-ns-hook的函數(shù):
    (defn test-ns-hook []
      (test
    -square)
      (arithmetic))
        這樣run-tests就會(huì)調(diào)用test-ns-hook按照給定的順序執(zhí)行指定的用例,避免了重復(fù)執(zhí)行。

        在你的測(cè)試代碼里明確調(diào)用run-tests執(zhí)行測(cè)試是一種方式,不過我們?cè)陂_發(fā)中更經(jīng)常使用的是lein來管理project,lein會(huì)將src和test分開,將你的測(cè)試代碼組織在專門的test目錄,類似使用maven的時(shí)候我們將main和test分開一樣。這時(shí)候就可以簡(jiǎn)單地調(diào)用:
            lein test
    命令來執(zhí)行單元測(cè)試,而不需要明確地在測(cè)試代碼里調(diào)用run-tests并指定ns。更實(shí)用的使用例子可以看一些開源項(xiàng)目的組織。

        單元測(cè)試?yán)镒鰉ock也是比較常見的需求,在clojure里做mock很容易,原來clojure.contrib有個(gè)mock庫,基本的原理都是利用binding來動(dòng)態(tài)改變被mock對(duì)象的功能,但是在clojure 1.3里,binding只能改變標(biāo)注為dynamic的變量,并且clojure.contrib被廢棄,部分被合并到core里面,Allen Rohner編譯了一個(gè)可以用于clojure 1.3的clojure.contrib,不過需要你自己install到本地倉庫,具體看這里。不過clojure.contrib.mock哪怕使用1.2的編譯版本其實(shí)也是可以的。

        clojure.contrib最重要的是expect宏,它類似EasyMock里的expect方法,看一個(gè)例子:
    (use [clojure.contrib.mock :only [times returns has-args expect]])

    (deftest test
    -square2
      (expect [square (has
    -args [number?] (times 2 (returns 9)))]
              (
    is (= 9 (square 4)))))

        has-args用來檢測(cè)square的參數(shù)是不是number,times用來指定預(yù)期調(diào)用的次數(shù),而returns用來返回mock值,是不是很像EasyMock?因?yàn)槲覀冞@個(gè)測(cè)試只調(diào)用了square一次,所以這個(gè)用例將失敗:
    Testing example
    "Unexpected invocation count. Function name: square expected: 2 actual: 1"
       這個(gè)例子要在Clojure 1.3里運(yùn)行,需要將square定義成dynamic:
    (defn ^:dynamic square [x]
      (
    * x x))
       否則會(huì)告訴你沒辦法綁定square:
    actual: java.lang.IllegalStateException: Can't dynamically bind non-dynamic var: example/square


        額外提下,還有個(gè)輕量級(jí)的測(cè)試框架expections可以看一下,類似Ruby Facker的facker庫提供一些常見的模擬數(shù)據(jù),如名稱地址等。
       
         轉(zhuǎn)載請(qǐng)注明出處:http://www.tkk7.com/killme2008/archive/2012/02/15/370040.html

       
    主站蜘蛛池模板: 99在线热视频只有精品免费| 456亚洲人成影院在线观| 无码国模国产在线观看免费| 日本视频免费高清一本18| 成人久久久观看免费毛片| 亚洲综合小说另类图片动图| 亚洲一区二区三区四区在线观看| 国产精品亚洲高清一区二区| 日韩一级视频免费观看| 久草免费在线观看视频| 国产成人一区二区三区视频免费| 九九免费精品视频在这里| 亚洲高清毛片一区二区| 中文文字幕文字幕亚洲色| 亚洲国产夜色在线观看| 1区1区3区4区产品亚洲| 亚洲AV无码成人精品区在线观看| 中文字幕日韩亚洲| 亚洲人成影院在线观看| 亚洲黄黄黄网站在线观看| xvideos亚洲永久网址| 国产精品国产自线拍免费软件| 成人人观看的免费毛片| 久久天天躁狠狠躁夜夜免费观看| 精品熟女少妇a∨免费久久| 青青青国产手机频在线免费观看| 最好免费观看高清在线| 免费黄网站在线观看| 精品视频一区二区三区免费| 久久午夜免费鲁丝片| 香港a毛片免费观看| 久久综合国产乱子伦精品免费| 久9这里精品免费视频| 三年片在线观看免费观看大全动漫| 久久免费视频观看| 无码日韩精品一区二区免费暖暖| 中文字幕无码免费久久| 99re热精品视频国产免费| 永久在线免费观看| 久久综合AV免费观看| 国产精品免费视频一区|