【问题标题】:How to test the behaviour of an akka actor, if it reads from `stdin` and writes to `stdout`?如果从`stdin`读取并写入`stdout`,如何测试akka actor的行为?
【发布时间】:2019-11-13 13:31:47
【问题描述】:

我正在编写一个 UCI 解释器,作为 Akka 有限状态机。根据规范,解释器必须将其输出写入stdout,并从stdin 获取输入。

我有一个演员的测试服,我可以测试其行为的某些方面(与消息相关),但我不知道如何捕获stdout 来做出断言,也不知道如何向它发送输入通过stdin。我已尽我所能探索了最大规模的 API,但找不到如何实现我所需要的。

这是当前的测试类:

package org.chess

import akka.actor.ActorSystem
import akka.testkit.{TestKit, TestProbe}
import org.chess.Keyword.Quit
import org.scalatest.wordspec.AnyWordSpecLike
import org.scalatest.{BeforeAndAfterAll, Matchers}

import scala.concurrent.duration._
import scala.language.postfixOps

class UCIInterpreterSpec(_system: ActorSystem)
  extends TestKit(_system)
    with Matchers
    with AnyWordSpecLike
    with BeforeAndAfterAll {

  def this() = this(ActorSystem("UCIInterpreterSpec"))

  override def afterAll: Unit = {
    super.afterAll()
    shutdown(system)
  }

  "A UCI interpreter" should {

    "be able to quit" in {
      val testProbe = TestProbe()
      val interpreter = system.actorOf(UCIInterpreter.props)
      testProbe watch interpreter
      interpreter ! Command(Quit, Nil)
      testProbe.expectTerminated(interpreter, 3 seconds)
    }

  }

}

当然,知道解释器可以退出是有用的……但不是很有用。我需要测试,例如,如果将字符串isready 发送给解释器,它会返回readyok

我是否有可能通过使用 akka.testkit 而不是更简单的框架使测试过于复杂?为了简单起见,我想继续使用单一的测试框架,并且我需要测试系统的许多其他与参与者相关的元素,所以如果可以在不离开 akka-testkit/scalatest 域的情况下解决这个问题,那就太棒了。

任何帮助将不胜感激。提前致谢。

【问题讨论】:

  • 祝 UCI 好运,如果可行,请开源这些东西 ;)
  • 谢谢!它可以在github.com/bruno-unna/chess 获得(目前在uci-implementation 分支上工作)。我还没有定义许可证,但它当然是开源的。

标签: scala akka stdout scalatest testkit


【解决方案1】:

您需要更改 Actor 的设计。

Actor 不应直接读取stdin 或写入stdout。相反,在Props 中提供提供输入和接受输出的参与者对象。 stdin 可能类似于 () => String ,每次需要输入时都会调用它。 stdout 可以是每次生成输出时调用的String => Unit。或者,您可以使用 Streams 或类似的构造,这些构造被设计为抽象的数据源和接收器。

在生产代码中,您传递使用stdinstdout 的对象,但对于测试代码,您传递读取和写入内存缓冲区的对象。然后,您可以检查 Actor 是否使用了适当的输入,以及 Actor 是否生成了适当的输出。

【讨论】:

  • 完全同意这个关于使用控制反转来实现这一点的答案。 IE。传递可以从中读取的抽象内容,而不是硬编码 stdin 依赖项。在某些情况下,当您没有该控制权时,例如在测试库时,您可能希望使用以下方法重新分配 stdin/stdoutdocs.oracle.com/javase/7/docs/api/java/lang/…System.setIn(...InputStream...)
  • 也许更强大的重新分配方法是:stackoverflow.com/a/56523167/1972909
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
  • 2011-05-05
  • 1970-01-01
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多