Scala Mockito Guice and Partial Mocking .... methods are called twice

I have the following code written in Scala, Guice, Mockito and ScalaTest

import javax.inject.Singleton
import com.google.inject.Inject
@Singleton
class TestPartialMock @Inject()(t1: Test1, t2: Test2) {
   def test3() = "I do test3"
   def workHorse() : List[String] = {
      println("+++++ came inside ++++++++")
      List(t1.test1(), t2.test2(), test3())
   }
}


class MainModule extends ScalaModule {
   override def configure() = {
      bind[Test1]
      bind[Test2]
      bind[TestPartialMock]
   }
}

      

and I wrote unit test cases with partial mockery

class PartialMockTest extends FunSpec with Matchers {
   describe("we are testing workhorse but mock test3") {
      it("should return mock for test3") {
         val module = new TestModule
         val injector = Guice.createInjector(module)
         val tpm = injector.getInstance(classOf[TestPartialMock])
         val result = tpm.workHorse()
         result should contain ("i do test2")
         result should contain ("i do test1")
         result should contain ("I am mocked")
         result should not contain ("I do test3")
      }
   }
}

class TestModule extends AbstractModule with ScalaModule with MockitoSugar {
   override def configure() = {
      val module = new MainModule()
      val injector = Guice.createInjector(module)
      val realobject = injector.getInstance(classOf[TestPartialMock])
      val x = spy(realobject)
      when(x.test3()).thenReturn("I am mocked")
      when(x.workHorse()).thenCallRealMethod()
      bind(classOf[TestPartialMock]).toInstance(x)
   }
}

      

My tests are successful and I can see that it mocks the correct set of methods and calls the actual implementation of the correct set of methods. BUT when I look at the output I see

info] Compiling 5 Scala sources to /Users/IdeaProjects/GuicePartialMock/target/scala-2.12/classes...
[info] Compiling 1 Scala source to /Users/IdeaProjects/GuicePartialMock/target/scala-2.12/test-classes...
+++++ came inside ++++++++
+++++ came inside ++++++++
[info] PartialMockTest:
[info] we are testing workhorse but mock test3
[info] - should return mock for test3
[info] Run completed in 2 seconds, 92 milliseconds.

      

Why do I see the print operator came inside

twice?

Edit ::

Based on Tavian's recommendation ... this is the last code that worked

class TestModule extends AbstractModule with ScalaModule with MockitoSugar {
   override def configure() = {
      val module = new MainModule()
      val injector = Guice.createInjector(module)
      val realobject = injector.getInstance(classOf[TestPartialMock])
      val x = spy(realobject)
      when(x.test3()).thenReturn("I am mocked")
      bind(classOf[TestPartialMock]).toInstance(x)
   }
}

      

+3


source to share


2 answers


For spies, you need to be careful with expressions like

when(x.workHorse()).thenCallRealMethod()

      

because it is x.workHorse()

actually called in this expression! x

does not "know" that it is inside the call when()

, since the expression is omitted like this:

tmp1 = x.workHorse();
tmp2 = when(tmp1);
tmp3 = tmp2.thenCallRealMethod();

      



Instead, you can write

doCallRealMethod().when(x).workHorse()

      

which will suppress the call to the real implementation workHorse()

.

But , you don't need to do any of this in this example: - Calling real methods - default spy behavior.

+2


source


As you mentioned in the title of your question, you have a combination of three technologies. There are actually 4 technologies including a build tool that is used to run the test. You can isolate the problem with

1) Remove Guice and build everything directly



2) Run the code as a simple application instead of running as a test with sbt / gradle / maven.

It also makes sense to print the stack trace along with the message came inside

to find the caller.

-1


source







All Articles