Search code examples
javamockitojunit4weld

Junit 4 scope of @Mock in @Produces methods


Why do mocked objects appear "locked" after test-class instaciation and null in @Produced methods, if mocked with annotation @Mock

public class MyTest {

   @Rule
   public MockitoRule rule = MockitoJUnit.rule();

   @Rule
   public WeldInitiator weld = WeldInitiator.from(MyTest.class).build();

   //@Mock <-- this wont work. Will be null in the @Produces methods
   private ClassThatSutInjects sutInject= mock(ClassThatSutInjects.class);

   private NeedsTest sut;

   @Before
   public void setup() {
      sut = weld.select(NeedsTest.class).get();
   }

   @Test
   public void doesThisWork() {
      //Arrange
      //Mockito.when(sutInject.multiply(anyInt()))
      // .thenReturn(3);//this has no effect on the mock returned by @Produces

      //Act
      sut.doThis(1234);

      //Assert

  }

  @Produces
  public ClassThatSutInjects mockThatClass() {
      Mockito.when(sutInject.multiply(anyInt())).thenReturn(100);   //<-- this works
      return sutInject;
  }

}

public class NeedsTest {
   @Inject
   ClassThatSutInjects someClass

   public void doThis(int number) {
      return someClass.multiply(number);
   }

}

Two things puzzle me, that I would like some help in understanding:

1) @Mock (annotated fields) are null inside @Producer methods, but initalized if I use = Mockito.mock(xxx.class) instead. From what I gather this has to do with when notation is carried out vs. when @Rule are applied. More details would be appreciated...

2) I would very much like to be able to make the mock do different things in different test-cases, but it seems impossible since the @Produces methods is "stuck in the past" when mockito.when() hadn't been applied yet. How can i "arrange" pr. test-case? Having one test-class pr. test-case will become un-maintainable over time..to much code clutter.

EDIT: I have found out that making my mocked objects static, makes it possible to setup my mocked object pr. test method. I did a debug run and noticed that the object returned by the producer was not the same instance as used in jUnit @Test - apparently @Produces is run on another instance of the MyTest class...still doesn't really make sense to me, so still: if anyone has some knowledge, please share it.


Solution

  • As you already observed a producer is run on a different instance of the object.

    Source (Chapter 8.1 Scope of a producer method):

    A producer method does not inherit the scope of the bean that declares the method. There are two different beans here: the producer method, and the bean which declares it. The scope of the producer method determines how often the method will be called, and the lifecycle of the objects returned by the method. The scope of the bean that declares the producer method determines the lifecycle of the object upon which the producer method is invoked.

    Making the field static works around it, but isn't really a nice solution.