3

我正在尝试使用需要休眠以使后台进程继续进行的 ert 设置一些测试。我试过使用sleep-forand accept-process-output。两者都不可靠。这是一个小例子。

此测试仅休眠 5 秒,然后检查是否至少经过了 3 秒。使用sleep-for它立即完成并失败。如果shell-command未注释,则需要预期的 5 秒并成功!这里发生了什么?

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    ;(shell-command "sleep 5")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))

编辑:

当我测试前面的示例时,我的环境中一定有一些奇怪的东西。这个稍作改动的示例包含一个后台进程,就像我需要测试的那样,但失败了。我以交互方式和使用命令对其进行了测试:

emacs --batch -l example.el -f ert-run-tests-batch-and-exit
(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "echo" "*echo*" "echo" "hello world")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))

输出是:

Test timetest condition:
    (ert-test-failed
     ((should
       (< now
          (- ... 3)))
      :form
      (< 55177 55174)
      :value nil))
   FAILED  1/1  timetest

Ran 1 tests, 0 results as expected, 1 unexpected (2013-02-05 09:57:29+0000)

1 unexpected results:
   FAILED  timetest

编辑2:

似乎表明进程输出的新版本足以中断sleep-for

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "yes" "*yes*" "yes")
    (sleep-for 1) ;; This sleep-for may be interrupted by process *output*
    (sleep-for 5) ;; This sleep-for is also interrupted
    (should (< now (- (cadr (current-time)) 3)))))

编辑3:

怀着沉重的心情,我发布了另一个版本:

(ert-deftest timetest ()
  (let ((now (cadr (current-time)))
        (process-connection-type nil))
    (start-process "tmp" "*tmp*" "bash" "-c" "sleep 1; echo hi")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))

似乎很明显sleep-for不能依靠阻止。

4

4 回答 4

6

我认为sleep-for当进程退出时会中断。

以下测试失败,因为sleep-for2 秒后中断。

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "sleep" "*sleep*" "sleep" "2") ;; Fail
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))

但随后的测试通过了,因为sleep-for4 秒后中断。

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "sleep" "*sleep*" "sleep" "4") ;; Success
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))

所以我认为你可以编写如下测试

(ert-deftest timetest ()
  (let ((now (cadr (current-time))))
    (start-process "echo" "*echo*" "echo" "hello world")
    (sleep-for 1) ;; This sleep-for may be interrupted by process exited
    (sleep-for 5) ;; This sleep-for can sleep 5 seconds
    (should (< now (- (cadr (current-time)) 3)))))

编辑1

通过设置process-connection-type为 来通过第二次测试nil。(但我无法理解这种行为)

(ert-deftest timetest ()
  (let ((now (cadr (current-time)))
        (process-connection-type nil))
    (start-process "yes" "*yes*" "yes")
    (sleep-for 5)
    (should (< now (- (cadr (current-time)) 3)))))

请看文档

编辑2

在第 3 次测试中,我们需要 3次,sleep-for因为sleep-for被中断了 2 次,但这很脆弱。所以我写测试如下。sleep-for如果中断多次,则可以通过此测试。我使用float-time而不是current-time 因为第二个元素current-time可能会环绕。

(ert-deftest timetest ()
  (let ((now (float-time))
        (process-connection-type nil))
    (start-process "tmp" "*tmp*" "bash" "-c" "sleep 1; echo hi")
    (while (< (- (float-time) now) 5)
      (sleep-for 1))
    (should (< now (- (float-time) 3)))))
于 2013-02-06T01:26:23.273 回答
2

此错误将在下一个 Emacs(25.1?24.6??)中修复。请参阅2015 年 6 月的此提交。(不过,我实际上还没有尝试过。)

直到它得到修复,使用

(call-process "/usr/bin/sleep" nil nil nil "<seconds>")

而不是“睡觉”。这是可靠的。

错误报告在原始(#15990) 和重复(#20935) 中找到,其中报告了修复。

于 2013-12-01T02:18:13.863 回答
2

我刚刚复制到 *scratch* 并使用ert-run-tests-interactively. 我无法重现您的问题。您是否有旧版本的测试在记忆中挥之不去?

编辑:我在 OS X 10.8 上使用 Emacs 24.2.1

更新:运行更新的代码。一些非常奇怪的事情正在发生。我大约有 1/4 的跑步成功了。

更新:我可以验证@syohex 的答案:添加第二个电话sleep-for对我有用。

于 2013-02-05T05:33:10.620 回答
0

看看https://github.com/rejeep/ert-async.el

然后你可以做这样的事情:

(ert-deftest-async timetest (done)
  (call-async-command done))
于 2015-06-17T09:15:35.420 回答