Clojure世界:单元测试
首先看一个最简单的例子,定义一个函数square来计算平方,然后我们测试这个函数:
(ns example
(:use [clojure.test :only [deftest is run-tests]]))
;;定义函数
(defn square [x]
(* x x))
;;测试函数
(deftest test-square
(is (= 4 (square 2)))
(is (= 9 (square -3))))
;;运行测试
(run-tests \'example)
执行输出:
Testing example
Ran 1 tests containing 2 assertions.
0 failures, 0 errors.
这个小例子基本说明了clojure.test的主要功能。首先是断言is,类似JUnit里的assertTrue,用来判断form是否为true,它还可以接受一个额外的msg参数来描述断言:
(is (thrown-with-msg? RuntimeException #"java.lang.String cannot be cast to java.lang.Number" (square "a")))
(are
(= 0 (square 0))
(= 1 (square 1))))
其次,我们用deftest宏定义了一个测试用例,deftest定义的测试用例也可以组合起来:
(is (= 4 (+ 2 2)))
(is (= 7 (+ 3 4))))
(deftest subtraction
(is (= 1 (- 4 3)))
(is (= 3 (- 7 4))))
(deftest arithmetic
(addition)
(subtraction))
但是组合后的tests运行就不能简单地传入一个ns,而需要定义一个test-ns-hook指定要跑的测试用例,否则组合的用例如上面的addition和subtraction会运行两次。我们马上谈到。
定义完用例后是运行测试,运行测试使用run-tests,可以指定要跑测试的ns,run-tests接受可变参数个的ns。刚才提到,组合tests的时候会有重复运行的问题,要防止重复运行,可以定义一个test-ns-hook的函数:
(test-square)
(arithmetic))
在你的测试代码里明确调用run-tests执行测试是一种方式,不过我们在开发中更经常使用的是lein来管理project,lein会将src和test分开,将你的测试代码组织在专门的test目录,类似使用maven的时候我们将main和test分开一样。这时候就可以简单地调用:
单元测试里做mock也是比较常见的需求,在clojure里做mock很容易,原来clojure.contrib有个mock库,基本的原理都是利用binding来动态改变被mock对象的功能,但是在clojure 1.3里,binding只能改变标注为dynamic的变量,并且clojure.contrib被废弃,部分被合并到core里面,Allen Rohner编译了一个可以用于clojure 1.3的clojure.contrib,不过需要你自己install到本地仓库,具体看这里。不过clojure.contrib.mock哪怕使用1.2的编译版本其实也是可以的。
clojure.contrib最重要的是expect宏,它类似EasyMock里的expect方法,看一个例子:
(deftest test-square2
(expect [square (has-args [number?] (times 2 (returns 9)))]
(is (= 9 (square 4)))))
has-args用来检测square的参数是不是number,times用来指定预期调用的次数,而returns用来返回mock值,是不是很像EasyMock?因为我们这个测试只调用了square一次,所以这个用例将失败:
"Unexpected invocation count. Function name: square expected: 2 actual: 1"
(* x x))
额外提下,还有个轻量级的测试框架expections可以看一下,类似Ruby Facker的facker库提供一些常见的模拟数据,如名称地址
建议继续学习:
- web项目和单元测试 (阅读:3401)
- Clojure世界:XML处理 (阅读:1979)
- Linux下c/c++项目代码覆盖率的产生方法 (阅读:2076)
- Clojure世界:Http Client (阅读:1982)
- Clojure世界:文件IO (阅读:1860)
- 单元测试中的Fluent Interface (阅读:1731)
- Clojure世界:如何做性能测试 (阅读:1742)
- Clojure世界:使用rlwrap增强REPL (阅读:1565)
- Clojure世界:静态代码分析 (阅读:1631)
- Clojure世界:API文档生成 (阅读:1647)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:dennis 来源: BlogJava-庄周梦蝶
- 标签: Clojure 单元测试
- 发布时间:2012-03-04 17:54:13
- [46] 界面设计速成
- [40] 视觉调整-设计师 vs. 逻辑
- [40] Oracle MTS模式下 进程地址与会话信
- [38] android 开发入门
- [38] IOS安全–浅谈关于IOS加固的几种方法
- [36] 程序员技术练级攻略
- [36] 如何拿下简短的域名
- [35] 图书馆的世界纪录
- [35] 【社会化设计】自我(self)部分――欢迎区
- [32] 读书笔记-壹百度:百度十年千倍的29条法则