首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建用户提示并模拟交互

创建用户提示并模拟交互
EN

Stack Overflow用户
提问于 2016-10-31 22:23:11
回答 1查看 111关注 0票数 1

我有以下代码(为了这个问题我已经简化了):

代码语言:javascript
复制
  def openFile(directory: File): Try[String] = {
      var input = ""
      do {
        input = readLine("prompt>")
        println("alibaba.txt: 100%")
      } while(input != ":quit")
   }

工作流程是这样的:

用户会得到一个提示:

prompt>

用户编写alibaba,然后按enter键

用户可以看到:

代码语言:javascript
复制
alibaba.txt: 100%
prompt>

一切:

代码语言:javascript
复制
prompt>alibaba
alibaba.txt: 100%
prompt>

现在,我想测试一下它。

我编写了以下代码来测试用户交互:

代码语言:javascript
复制
  test("simulate user input from readline") {
    val prompt = new Prompt()
    prompt.openFile(new File("../resources"))

    val in = new ByteArrayInputStream("alibaba\n".getBytes)
    System.setIn(in)

    val scanner: Scanner = new Scanner(System.in)
    val programResponse: String = scanner.nextLine()
    println("programResponse: " + programResponse)

    System.setIn(System.in)
    assert(programResponse == "alibaba.txt: 100%")
  }

然而,我得到了这个结果,我很困惑:

代码语言:javascript
复制
"alibaba[]" did not equal "alibaba[.txt: 100%]"

那么,如何让测试模拟用户交互呢?

如何读取我的程序所写的内容?

EN

回答 1

Stack Overflow用户

发布于 2016-11-01 04:34:56

我想你应该以一种简单的可测试的方式来组织你的代码,这意味着你应该将IO提取到更高的抽象中。

出于演示目的,我将您的示例稍微修改为以下代码:

代码语言:javascript
复制
import java.util.Scanner

object YourObject {

  def consoleMethod(in: () => String = new Scanner(System.in).nextLine,
                    out: String => Unit = System.out.println): Unit = {
    var input = ""
    do {
      out("prompt>")
      input = in()
      out("alibaba.txt: 100%")
    } while (input != ":quit")
  }
}

让我们把它分解一下

  • in: () => String = new Scanner(System.in).nextLine代表我们的用户输入源。默认情况下,它是System.in.
  • out: String => Unit = System.out.println代表我们的输出源。缺省情况下为System.out

让我们测试一下当用户立即进入":quit"时的场景:

代码语言:javascript
复制
import org.scalatest.{Matchers, WordSpec}

class Test extends WordSpec with Matchers {

  "We" should {
    "simulate user input from readline" in {
      var outputs = List.empty[String]
      def accumulate(output: String): Unit = outputs = outputs :+ output

      val in: () => String = () => ":quit"
      val out: String => Unit = accumulate _

      YourObject.consoleMethod(in, out)

      outputs shouldBe List("prompt>", "alibaba.txt: 100%")
    }
  }
}

如果您想要更多的控制,可以使用scalamock

在这种情况下,我们可以模拟、inout,让它们按照我们需要的方式运行。

代码语言:javascript
复制
val in = mock[() => String]
val out = mock[String => Unit]

设置来源预期:

代码语言:javascript
复制
(in.apply _).expects().anyNumberOfTimes().onCall(_ => ":quit")

现在我们想要设置out来记录我们将要写入的内容:

代码语言:javascript
复制
var outputs = List.empty[String]
def accumulate(output: String): Unit = outputs = outputs :+ output

(out.apply _)
  .expects(new FunctionAdapter1[String, Boolean](_ => true))
  .anyNumberOfTimes()
  .onCall(accumulate _)

太好了,现在让我们设置一下期望:

代码语言:javascript
复制
outputs shouldBe List("prompt>", "alibaba.txt: 100%")

的全部源代码的测试

代码语言:javascript
复制
import org.scalamock.function.FunctionAdapter1
import org.scalamock.scalatest.MockFactory
import org.scalatest.{Matchers, WordSpec}

class Test extends WordSpec with Matchers with MockFactory {

  "We" should {
    "simulate user input from readline" in {
      val in = mock[() => String]
      val out = mock[String => Unit]

      (in.apply _).expects().anyNumberOfTimes().onCall(_ => ":quit")

      var outputs = List.empty[String]

      def accumulate(output: String): Unit = outputs = outputs :+ output

      (out.apply _)
        .expects(new FunctionAdapter1[String, Boolean](_ => true))
        .anyNumberOfTimes()
        .onCall(accumulate _)

      YourObject.consoleMethod(in, out)

      outputs shouldBe List("prompt>", "alibaba.txt: 100%")
    }
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40344117

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档