Test a nested method call on a mocked class using ScalaMock
我对ScalaMock和嘲讽都是陌生的。我试图测试一种方法,该方法在另一个(模拟的)类中调用一个方法,然后在返回的对象上调用一个方法。
详细资料:
所以我正在使用ScalaTest,此测试涉及五个类...
我正在测试的子指令
1 2 3 4 5 6 7 8 9 10 11 12 13 | class SubInstruction(label: String, val result: Int, val op1: Int, val op2: Int) extends Instruction(label,"sub") { override def execute(m: Machine) { val value1 = m.regs(op1) val value2 = m.regs(op2) m.regs(result) = value1 - value2 } } object SubInstruction { def apply(label: String, result: Int, op1: Int, op2: Int) = new SubInstruction(label, result, op1, op2) } |
必须为测试而模拟的机器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | case class Machine(labels: Labels, prog: Vector[Instruction]) { private final val NUMBEROFREGISTERS = 32 val regs: Registers = new Registers(NUMBEROFREGISTERS) override def toString(): String = { prog.foldLeft("")(_ + _) } def execute(start: Int) = start.until(prog.length).foreach(x => prog(x) execute this) } object Machine extends App { if (args.length == 0) { println("Machine: args should be sml code file to execute") } else { println("SML interpreter - Scala version") val m = Translator(args(0)).readAndTranslate(new Machine(Labels(), Vector())) println("Here is the program; it has" + m.prog.size +" instructions.") println(m) println("Beginning program execution.") m.execute(0) println("Ending program execution.") println("Values of registers at program termination:") println(m.regs +".") } } |
注册构造Machine对象所需的寄存器
1 2 3 4 5 6 7 8 9 |
我作为原始Machine类创建的MockableMachine没有空的构造函数,因此(据我了解)不能被嘲笑
最后是我的测试类SubInstructionTest,该类可以编译但引发以下异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class SubInstructionTest extends FlatSpec with MockFactory with Matchers { val label1 ="f0" val result1 = 25 val op1_1 = 24 val op2_1 = 20 val sub1 = SubInstruction(label1, result1, op1_1, op2_1) "A SubInstruction" should"retrieve the operands from the correct registers in the given machine" + "when execute(m: Machine) is called, and perform the operation saving the" + "result in the correct register." in { val mockMachine = mock[MockableMachine] inSequence { (mockMachine.regs.apply _).expects(op1_1).returning(50) (mockMachine.regs.apply _).expects(op2_1).returning(16) (mockMachine.regs.update _).expects(result1, 34) } sub1.execute(mockMachine) } } |
抛出:
java.lang.NoSuchMethodException:Registers.mock $ apply $ 0()
--
我一直在寻找一种简单的方法来模拟该类达数小时之久,但没有发现任何东西。暂时,我已经解决了以下详细说明的变通办法,但给人的印象是,模拟将为测试我的SubInstruction类的问题提供一个不太复杂的解决方案。
解决方法:
删除MockableMachine类,并创建一个CustomMachine类,该类扩展Machine并用构造时提供的模拟寄存器替换寄存器值。
1 2 3 4 |
我作为原始对象创建的MockableRegisters类没有空的构造函数,因此(据我了解)不能被嘲笑
和SubInstructionTest类以稍微不同的方式编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class SubInstructionTest extends FlatSpec with MockFactory with Matchers { val label1 ="f0" val result1 = 25 val op1_1 = 24 val op2_1 = 20 val sub1 = SubInstruction(label1, result1, op1_1, op2_1) "A SubInstruction" should"retrieve the operands from the correct registers in the given machine" + "when execute(m: Machine) is called, and perform the operation saving the" + "result in the correct register." in { val mockRegisters = mock[MockableRegisters] val machine = new CustomMachine(mockRegisters) inSequence { (mockRegisters.apply _).expects(op1_1).returning(50) (mockRegisters.apply _).expects(op2_1).returning(16) (mockRegisters.update _).expects(result1, 34) } sub1.execute(machine) } } |
如前所述,这对我来说似乎是一种解决方法,难道没有一种更简单的方法(也许与我最初的尝试类似)吗?
我刚刚包含了问这个问题的基本代码,但是您可以在我的GitHub帐户上找到完整的代码。
我认为Scalamock并不支持模拟嵌套对象。 您必须模拟第一个调用返回的对象,这是您的工作示例所做的。
FWIW,Mockito支持这一点。 搜索