我可以对 ELisp 函数进行文档测试吗?

Can I doc-test ELisp functions?

我喜欢 doc-tests 的 Python 功能,可以独立测试功能。 Emacs Lisp 是否有类似的东西,或者我可以用某种方式模仿它吗?

例如,此函数从 Org 模式时钟段获取时间戳:

(defun org-get-timestamps (line)
  "Parses a clock segment line and returns the first and last timestamps in a list."
  (let* ((org-clock-regexp (concat "CLOCK: " org-ts-regexp3 "--" org-ts-regexp3))
     (t1 (if (string-match org-clock-regexp line)
         (match-string 1 line)
           (user-error "The argument must have a valid CLOCK range")))
     (t2 (match-string 9 line)))
    (cons t1 (cons t2 '()))))

我想要一个文档测试,例如:

(org-get-timestamps "CLOCK: [2019-09-26 Thu 00:29]--[2019-09-26 Thu 01:11] =>  0:42")
("2019-09-26 Thu 00:29" "2019-09-26 Thu 01:11")

测试一下 user-error 也很好。

我也想确保任何重构都通过文档测试,所以它也是一个回归测试。

存在吗?

Python doctest 的一个重要特征是它的输入看起来像 Python 交互式 REPL 会话,如 doctest documentation:

中所述

The doctest module searches for pieces of text that look like interactive Python sessions, and then executes those sessions to verify that they work exactly as shown.

我不知道有任何类似这样的 elisp 工具,但我认为您可以使用 Emacs Lisp Regression Testing (ERT) framework 实现您想要的,它支持交互式和批处理测试执行。

要测试 org-get-timestamps 函数,您可以像这样定义一个测试:

(require 'ert)

(ert-deftest org-timestamp-test ()
  (should (equal
           (org-get-timestamps "CLOCK: [2019-09-26 Thu 00:29]--[2019-09-26 Thu 01:11] => 0:42")
           '("2019-09-26 Thu 00:29" "2019-09-26 Thu 01:11"))))

为了 运行 交互式测试,您可以键入 M-x ert,按回车键,然后再次按回车键 select 所有测试使用默认 t 参数或将测试名称键入 运行 并按回车键,测试结果将显示在 *ert* 缓冲区中:

Selector: org-timestamp-test
Passed:  1
Failed:  0
Skipped: 0
Total:   1/1

Started at:   2019-09-27 08:44:57-0400
Finished.
Finished at:  2019-09-27 08:44:57-0400

.

上面最后的点字符代表 运行 的测试。如果执行了多个测试,就会有多个点。

要运行以批处理模式测试,将其保存到文件org-timestamp-test.el并假设org-get-timestamps函数驻留在文件org-timestamps.el中,运行它在你的 shell 命令行中像这样:

emacs -batch -l ert -l org-timestamps.el -l org-timestamp-test.el -f ert-run-tests-batch-and-exit

测试结果随后显示在 shell 输出中:

Running 1 tests (2019-09-27 06:03:09-0700) passed 1/1 org-timestamp-test

Ran 1 tests, 1 results as expected (2019-09-27 06:03:09-0700)