想要很简单就对写的代码进行测试?本章将介绍如何编写自动化测试并查看代码的覆盖率。同时也介绍了在现在的持续集成服务(如 Travis CI 和 Coveralls)中插入自己的测试。
我们将使用一个成熟且设计良好的回归测试框架,叫做 Prove。Prove 不是唯一的测试框架,FiveAM也很受欢迎(参见 Turotial-Working-with-FiveAM) 这篇博客),同时还有很多其他的测试框架。我们喜欢 Prove 是因为它的文档及其可拓展报告(prove 的报告风格非同一般,而且可以拓展)。
warning: Prove has a couple limitations and will soon be obsolete. We advise to start with another test framework.
使用 Prove 进行测试
安装加载
Prove 在 quicklisp 中可以找到:
(ql:quickload :prove)
上面这条命令将会安装并加载 prove。
编写测试文件
(in-package :cl-user)(defpackage my-test(:use :cl:prove))(in-package :my-test)(subtest "Showing off Prove"(ok (not (find 4 '(1 2 3))))(is 4 4)(isnt 1 #\1))
Prove 的 API 包括下列测试函数: ok,is,isnt,is-values,is-type,like(检查正则表达式), is-print(检查是否是标准输出),is-error,is-expand,pass,fail,skip,subtest
运行测试文件
(prove:run #P"myapp/tests/my-test.lisp")(prove:run #P"myapp/tests/my-test.lisp" :reporter :list)
将会得到以下的结果:

运行一个测试
可以直接通过将测试文件编译来运行测试。在 Slime 中,通常是 C-c C-c 快捷键。
更多
Prove 还可以:
- 在 Travis CI 上运行,
- 修改输出的颜色,
- 报告测试时间,
- 修改默认测试函数,
- 设置阈值来减缓测试的运行,
- 一旦遇到异常,调出 CL debugger
- 与 ASDF 集成,因此可以在 REPL 中执行
(asdf:test-system)或(prove:run)(由同一个作者提供的 cl-project有相应的配置)
更多参见 Prove’s documentation!
交互式修复测试单元
Common Lisp 天然就是可交互的(所以才会有很多的解释器),并且测试框架也可以使用这个特性。这样的话,在测试失败是测试框架可以打开调试器(debugger),这样就可以检查堆栈追踪并能立即跳转到出错的那一行,对其进行修复,然后通过 restart 从之前出错的地方重新运行测试。
在 Prove 中,将 prove:*debug-on-error* 设为 t。
下面简短的视频展示了所有的一系列操作(使用的是 FiveAM):
注意,在 Debugger 中的操作如下:
<enter>展示更多的追踪(backtrace)信息v在追踪信息中跳转的相对应的行或函数- 更多选项可以查看菜单
代码覆盖率
代码覆盖率工具会输出个图形界面,通过这个界面可以知道代码哪部分被测试了,哪部分没有被测试:

Generating an html test coverage output
SBCL comes with a built-in module to do code coverage analysis:
sb-cover.
Coverage reports are only generated for code compiled usingcompile-file with the value of the sb-cover:store-coverage-data
optimization quality set to 3.
;;; Load SB-COVER(require :sb-cover);;; Turn on generation of code coverage instrumentation in the compiler(declaim (optimize sb-cover:store-coverage-data));;; Load some code, ensuring that it's recompiled with the new optimization;;; policy.(asdf:oos 'asdf:load-op :cl-ppcre-test :force t);;; Run the test suite.(prove:run :yoursystem-test)
Produce a coverage report, set the output directory:
(sb-cover:report "coverage/")
Finally, turn off instrumentation:
(declaim (optimize (sb-cover:store-coverage-data 0)))
You can open your browser at../yourproject/t/coverage/cover-index.html to see the report like
the capture above or like
this code coverage of cl-ppcre.
持续集成(continuous integration)
Travis CI 和 Coveralls
Travis 是在云端运行测试单元的服务,而 Coveralls 展示的是覆盖范围随时间的演变,同时也会展示 pull 请求将对覆盖范围缠身什么影响。
多亏了 cl-travis,我们可以轻松的在一个或多个解释器(ABCL、Allegro CL,SBCL、CMUCL、CCL以及ECL)进行测试。cl-coveralls 用来将输出的报告发不到服务上。cl-coveralls 支持在 SBCL 和Clozure CL 使用 Travis CI 和 Circle CI。
推荐阅读 lisp-lang.org 上关于“持续集成”]) 的详细说明。
在上述的链接中可以找到很多使用持续集成的例子,但如果只是想快速了解 Travis CI 和 Coveralls 的话,可以阅读:
Gitlab CI
Gitlab CI 是 Gitlab 的一部分,而且也能在 Gitlab.com 上使用,不管是共有库还是私有库。直接来看个简单的 .gitlab-ci.yml 吧:
image: daewok/lisp-develbefore_script:- apt-get update -qy- apt-get install -y git-core- git clone https://github.com/foo/bar ~/quicklisp/local-projects/test:script:- make test
Gitlab CI 是基于 Docker 的。通过 image 来告诉 Gitlab CI 使用 daewok/lisp-devel 镜像。这个镜像包含了 SBCL、ECL、CCL和BCL,同时也将 Quicklisp 安装在 home 目录下(/home/lisp/),因此可以直接使用 quickload。如果有兴趣的话,还有个更简单的选择。Gitlab 将加载镜像,克隆项目然后以管理员的权限进入到项目根目录下,之后在运行其他的命令。
test 是自定义的一个“任务”,script 关键词可以接受命令列表然后执行列表中的命令。
假设需要在运行测试前安装依赖库,before_scipt 会在任务开始前运行。在这,我们克隆一个 Quicklisp 中的一个库,要这么做的话首先的安装 git(Docker 镜像都很简单)。
可以定位自己所在的目录。如果已经安装了 Docker 并启动了 docker 的后台(sudo service docker start),可以运行下面的命令:
docker run --rm -it -v /path/to/local/code:/usr/local/share/common-lisp/source daewok/lisp-devel:latest bash
上面的命令会下载 Lisp 镜像(400Mb左右),将本地额代码挂在到镜像中的指定位置,同时切换到 lisp 这个容器的 bash 中,之后就可以试试 make test 了。
以下 Dockerfile 完整的示例:
image: daewok/lisp-develstages:- test- buildbefore_script:- apt-get update -qy- apt-get install -y git-core- git clone https://github.com/foo/bar ~/quicklisp/local-projects/test:stage: testscript:- make testbuild:stage: buildonly:- tagsscript:- make buildartifacts:paths:- some-file-name
在上面的 Dockerfile 中,定义了两个 步骤(stages)(参考环境):“test” 和 “build”,这两个步骤是一个接一个运行的。”build” 步骤只有在 “test” 步骤执行成功之后才会执行。
”build“ 只在推送新标签时才会运行,而不是每提交一次就运行一次。当 build 成功后,artifacts 中的 paths 中列出的文件就可以下载。可以从 Gitlab 的 Pipelines UI 或是一个 url 下在这些文件。这个操作只会下载最近一次 build 任务生成的文件:
https://gitlab.com/username/project-name/-/jobs/artifacts/master/raw/some-file-name?job=build
当管道穿过去之后,将会看到:

现在你已经可以使用 Gitlab CI 了。
