私は ScalaMock と一般的なモッキングの両方が初めてです。別の (モックされた) クラスのメソッドを呼び出してから、返されたオブジェクトのメソッドを呼び出すメソッドをテストしようとしています。
詳細な情報:
私は ScalaTest を使用しており、このテストには 5 つのクラスが含まれています...
私がテストしているSubInstruction
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)
}
テストのためにモックする必要があるマシン
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 オブジェクトの構築に必要なレジスタ
case class Registers(size: Int) {
val registers: Array[Int] = new Array(size)
override def toString(): String =
registers.mkString(" ")
def update(k: Int, v: Int) = registers(k) = v
def apply(k: Int) = registers(k)
}
元の Machine クラスとして作成した MockableMachine には空のコンストラクターがないため、(私が理解しているように)モックできません
class MockableMachine extends Machine(Labels(), Vector()){
}
そして最後に、コンパイルするが以下の例外をスローするテストクラス SubInstructionTest 。
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 クラスを削除し、Machine を拡張してレジスタ値を構築時に提供される mockedRegisters に置き換える CustomMachine クラスを作成します。
class CustomMachine (mockedRegister: Registers) extends Machine(Labels(), Vector()) {
override
val regs: Registers = mockedRegister
}
オリジナルとして作成した MockableRegisters クラスには空のコンストラクターがないため、(私が理解しているように)モックすることはできません
class MockableRegisters extends Registers(32) {
}
SubInstructionTest クラスは、わずかに異なる方法で記述されています。
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 アカウントで完全なコードを見つけることができます。