如何在emacs中测试交互函数?

10
我是一款Emacs包的维护者,该包的整个目的都与用户交互有关。每当我更改代码时,我必须手动测试它是否有效。如果能进行自动化测试就好了,但我不知道如何以所需的方式模拟用户输入。是否有一种交互式函数可以提示用户,然后用模拟打字(包括像C-j这样的组合键)来响应该提示呢?

2
也许你可以使用键盘宏 C-x ( "一些命令" C-x ) 并编辑它 C-x C-k RET - djangoliv
我的包实际上并没有提供一个命令,而是提供了一个替代completing-read的选择,因此我不能通过运行一个命令来测试它。 - Ryan C. Thompson
2个回答

7

新内容: 我已经重新实现了with-simulated-input宏,使用execute-kbd-macro,所以现在它也可以在批处理模式下工作。您可以在这里查看新的实现。

原始答案:

我在Emacs SX网站上的一个问题中找到了答案。基本上,您必须将所需的按键序列转换为正确的格式,并将其放入unread-command-events中。例如:

(let ((unread-command-events (listify-key-sequence (kbd "blu RET"))))
  (ido-completing-read "Select a color: " '("yellow" "blue")))

正确返回"blue"

需要注意的一件事是,你必须确保你的键序列一定会终止命令的交互部分,否则命令将会继续等待输入。确保终止的一种方法是在键序列末尾添加"C-g",以便在命令到达键序列末尾时中止该命令,如果命令已经完成,则任何未使用的输入都将在 let-bindings 超出范围时被丢弃,所以C-g事件不会发出错误信号。因此,更合适的测试可能是:

;; Runs successfully
(condition-case nil
    (let ((unread-command-events (listify-key-sequence (kbd "blu RET C-g"))))
      (ido-completing-read "Select a color: " '("yellow" "blue")))
  (quit (error "Reached end of `unread-command-events' without terminating")))

;; Throws an error
(condition-case nil
    (let ((unread-command-events (listify-key-sequence (kbd "blu C-g"))))
      (ido-completing-read "Select a color: " '("yellow" "blue")))
  (quit (error "Reached end of `unread-command-events' without terminating")))

这种方法的一个重要限制是,尽管它允许您完全非交互式地运行交互式函数,但在批处理模式下的emacs会话中,它将无法工作,可能是因为emacs在批处理模式下根本不处理键盘输入。


你让我的一天变得美好!谢谢! - Geradlus_RU
啊,忘了这个在批处理模式下行不通。真遗憾! - Geradlus_RU
1
@Geradlus_RU FYI,我已经发布了一个新的实现(链接如上),应该也可以批量模式工作。 - Ryan C. Thompson

2
您可以使用execute-kbd-macro和ERT。我在我的测试文件中实现了一个非常简单的实现。 实际上,这些测试看起来非常整洁 - 几乎就像我在交互式地按键一样:
(ert-deftest ivy-read ()
  (should (equal
           (ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
                     "C-m")
           "blue"))
  (should (equal
           (ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
                     "y C-m")
           "yellow"))
  (should (equal
           (ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
                     "y DEL b C-m")
           "blue"))
  (should (equal
           (ivy-with '(ivy-read "pattern: " '("blue" "yellow"))
                     "z C-m")
           "z")))

看了你的 ivy-with 实现,似乎需要定义一个命令并将其绑定到一个键上,这是可行的,但如果用户想在他们的 Emacs 会话中运行测试,这会有点混乱。 - Ryan C. Thompson
1
我已经采用了您使用execute-kbd-macro 的概念,并重写成尽可能卫生的方式 这里。 它使用 cl-letf 词法地定义命令,确保命令的绑定不会干扰普通键绑定,使用 cl-gensym 来保证没有名称冲突,并处理不完整的输入(例如,在结尾处没有按下RET)或过度的输入(例如,按下两次RET,而一次就足够了)。 结果是...有点长,但不应泄漏任何抽象的部分。 - Ryan C. Thompson
2
那个链接现在已经失效了,但是看起来被 with-simulated-input 替代了,可以在 https://github.com/DarwinAwardWinner/with-simulated-input 和 MELPA 上找到。 - Sam Brightman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接