Search code examples
scalascalatestscalamock

Remocking a mock function


Say I have trait:

trait A {
    def a(): Boolean
}

And mock + testcase:

trait Fixture {
    val mockA = mock[A]
    (mockA _).returns(true)
}

"mock must return true" in new Fixture {
    mockA() must equal(true)
}

Now, I want to re-mock the value to false for a single test in the same test suite

trait ChildFixture extends Fixture {
    (mockA _).returns(false) // this obviously doesn't work
}
"mock must return false" in new ChildFixture {
    mockA() must equal(false)
}

This is a very simplified example, I have a complex dependency chain of mocking fixtures. The obvious answer is to extract the mocking code for mockA into another fixture and then mix into the ones that should be true, then make a new Fixture for the specific test that should be false. Only issue is this is an onerous process given my test code. It is also possible to manually mock the return with an anonymous class and a var, but this does not seem very elegant and loses the function of Scala mock call validation.

Is it possible to restub an already-mocked object for a single test?


Solution

  • If you have a "complex dependency" of mocks, then I would suggest that instead of vals these mocks were defs which you could safely override, because you would call assign the result to val manually after potential rewrite. Also, all changes to such mock could be made in a block of code:

    trait A {
      def a(): Boolean
    }
    
    trait B {
      def b(): B
    }
    
    trait Fixture {
      def createMockA(): A = {
        val mocked = mock[A]
        (mocked.a _) returns true
        mocked
      }
    
      def createMockB(): B = {
        val mocked = mock[B]
        (mocked.b _) returns createMockA
        mocked
      }
    }
    
    trait FixtureChild extends Fixture {
      override def createMockA(): A = {
        val mocked = mock[A]
        (mocked.a _) returns false
        mocked
      }
    }
    
    "value must be overriden" in new FixtureChild {
      val b = createMockB()
      b.b().a() must beFalse
    }
    

    However if you have a "complex dependency chain of a mocking fixtures" I would treat that as a red flag that the code needs refactoring.