我有以下代码(我为了问题而简化了代码):
def openFile(directory: File): Try[String] = {
var input = ""
do {
input = readLine("prompt>")
println("alibaba.txt: 100%")
} while(input != ":quit")
}
工作流程如下:
用户收到提示:
prompt>
用户写alibaba
然后按Enter键
用户看到:
alibaba.txt: 100%
prompt>
一切:
prompt>alibaba
alibaba.txt: 100%
prompt>
现在,我想测试它。
我编写了以下代码来测试用户交互:
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%")
}
然而,我得到了这个结果,我很困惑:
"alibaba[]" did not equal "alibaba[.txt: 100%]"
那么如何让测试模拟用户交互?
我如何阅读我的程序写的内容?
答案 0 :(得分:1)
IMO你应该以一种简单可测试的方式构建你的代码,这意味着你应该将IO提取到更高的抽象。
出于演示目的,我将您的示例略微修改为以下代码:
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"
时测试场景:
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
:
在这种情况下,我们可以模拟 in
和out
来表现我们需要他们做的事情。
val in = mock[() => String]
val out = mock[String => Unit]
设置来源期望:
(in.apply _).expects().anyNumberOfTimes().onCall(_ => ":quit")
现在我们要设置out
来记录我们要编写的内容:
var outputs = List.empty[String]
def accumulate(output: String): Unit = outputs = outputs :+ output
(out.apply _)
.expects(new FunctionAdapter1[String, Boolean](_ => true))
.anyNumberOfTimes()
.onCall(accumulate _)
完美,现在让我们设定期望:
outputs shouldBe List("prompt>", "alibaba.txt: 100%")
测试的完整源代码:
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%")
}
}
}