在 Spock 中使用控制台输入模拟 InputStreamReader
Mocking InputStreamReader with console input in Spock
我有以下代码:
class MyWorker implements Runnable {
MyReader reader
Writer writer // java.io.Writer
CommandFactory commandFactory
@Inject
MyWorker(MyReader reader, Writer writer, CommandFactory commandFactory) {
super()
this.reader = reader
this.writer = writer
this.commandFactory = commandFactory
}
@Override
void run() {
try {
String line
while ((line = reader.readLine()) != null) {
// Commands have an execute method.
commandFactory.createCommand(line).execute(writer)
writer.flush()
}
} catch(InterruptedException ex) {
log.warn("${this} interrupted with: ${ExceptionUtils.getStackTrace(ex)}")
}
}
}
我正在尝试编写一个 Spock Specification
来验证按下换行符(Enter 键)时发生的几件事:
- 一个
command
被执行
- A
Writer
是 flush()
ed
这是我目前的情况:
class MyWorkerSpec extends Specification {
def "when enter key is pressed then a command is selected and executed and the writer is flushed"() {
given: "a running fixture with some mock dependencies"
MyReader reader = Mock()
Writer writer = Mock()
Command command = Mock()
CommandFactory commandFactory = Mock()
commandFactory.createCommand(Spock.ANY) << command // FIXME #1: Have it always return mock cmd
MyWorker worker = new MyWorker(reader, writer, commandSelector)
worker.run()
when: "the enter key is pressed"
// reader.input gives you a java.io.InputStream
reader.input.write << '\n' // FIXME #2: Send it a newline
then: "a command is executed"
1 * command.execute(Spock.ANY) // FIXME #4: How to specify "any"
and: "a writer is flushed"
1 * writer.flush() // FIXME #5 (how to guarante ordering of cmd -> flush)
}
}
如您所见,在给定 "any" 输入的情况下,我很难将模拟 CommandFactory
连接到 return 模拟 Command
。我也很难显式地向模拟 reader
的 InpuStream
发送换行符(以触发场景)。我也不确定测试方法是否强制排序(首先执行命令,然后刷新writer
)。
关于我哪里出错了有什么想法吗?
您应该使用 >>
运算符而不是 <<
。此外,在 Spock 中,any 是 _ 字符。
要创建始终 return 命令的模拟,请使用:
def commandFactory = Mock(CommandFactory) {
createCommand(_) >> command
}
你的 MyReader 应该被模拟为 return 另一个模拟的 InputStream :
def readerStream = Mock(InputStream) {
write() >> '\n'
}
def myReader = Mock(MyReader) {
input >> readerStream
}
最后,要订购交互,您应该使用多个 'then' 块:
then: "a command is executed"
1 * command.execute(_)
then: "a writer is flushed"
1 * writer.flush()
我有以下代码:
class MyWorker implements Runnable {
MyReader reader
Writer writer // java.io.Writer
CommandFactory commandFactory
@Inject
MyWorker(MyReader reader, Writer writer, CommandFactory commandFactory) {
super()
this.reader = reader
this.writer = writer
this.commandFactory = commandFactory
}
@Override
void run() {
try {
String line
while ((line = reader.readLine()) != null) {
// Commands have an execute method.
commandFactory.createCommand(line).execute(writer)
writer.flush()
}
} catch(InterruptedException ex) {
log.warn("${this} interrupted with: ${ExceptionUtils.getStackTrace(ex)}")
}
}
}
我正在尝试编写一个 Spock Specification
来验证按下换行符(Enter 键)时发生的几件事:
- 一个
command
被执行 - A
Writer
是flush()
ed
这是我目前的情况:
class MyWorkerSpec extends Specification {
def "when enter key is pressed then a command is selected and executed and the writer is flushed"() {
given: "a running fixture with some mock dependencies"
MyReader reader = Mock()
Writer writer = Mock()
Command command = Mock()
CommandFactory commandFactory = Mock()
commandFactory.createCommand(Spock.ANY) << command // FIXME #1: Have it always return mock cmd
MyWorker worker = new MyWorker(reader, writer, commandSelector)
worker.run()
when: "the enter key is pressed"
// reader.input gives you a java.io.InputStream
reader.input.write << '\n' // FIXME #2: Send it a newline
then: "a command is executed"
1 * command.execute(Spock.ANY) // FIXME #4: How to specify "any"
and: "a writer is flushed"
1 * writer.flush() // FIXME #5 (how to guarante ordering of cmd -> flush)
}
}
如您所见,在给定 "any" 输入的情况下,我很难将模拟 CommandFactory
连接到 return 模拟 Command
。我也很难显式地向模拟 reader
的 InpuStream
发送换行符(以触发场景)。我也不确定测试方法是否强制排序(首先执行命令,然后刷新writer
)。
关于我哪里出错了有什么想法吗?
您应该使用 >>
运算符而不是 <<
。此外,在 Spock 中,any 是 _ 字符。
要创建始终 return 命令的模拟,请使用:
def commandFactory = Mock(CommandFactory) {
createCommand(_) >> command
}
你的 MyReader 应该被模拟为 return 另一个模拟的 InputStream :
def readerStream = Mock(InputStream) {
write() >> '\n'
}
def myReader = Mock(MyReader) {
input >> readerStream
}
最后,要订购交互,您应该使用多个 'then' 块:
then: "a command is executed"
1 * command.execute(_)
then: "a writer is flushed"
1 * writer.flush()