0

I am trying to mock an Impl that contains 2 static members A, B, and a static method Utils.SomeMethod. I tried to mix PowerMock and Mockito initially but was not sure if this was causing the problem so I changed all refs to PowerMockito. I get unit test failures that mocks are not getting invoked. if I remove statics and just use Mockito then all tests succeed.

Here is a brief outline of the problem.

class Impl {

static A a;

static B b;

private static final String s = Utils.SomeMethod();

void mainMethod() {

   a.aMethod("foo");
   b.bMethod("bar");

}

}

So in my unit test I have

@PowerMockIgnore({"javax.net.ssl.*" , "javax.crypto.*"})
@RunWith(PowerMockRunner.class)
@PrepareForTest({Utils.class})
public class ImplTest {

  A a;
  B b;
  @Captor
  ArgumentCaptor<String> argumentCaptor;

  @BeforeClass
  static public void setUp() {
    PowerMockito.mockStatic(Utils.class);
    PowerMockito.when(Utils.SomeMethod()).thenReturn("test"); // works
  }

  @Before
  public void before() {
    a = PowerMockito.mock(A.class);
    b = PowerMockito.mock(B.class);
    impl = PowerMockito.mock(Impl.class);
    impl.setA(a); // I tried @Mock and @InjectMocks but seemed to not work on statics, works with non static members
    impl.setB(b);
 }

   @Test
   public void test() {
      PowerMockito.when(a
        .aMethod(any(String.class))
        .thenReturn("hmm");

    PowerMockito.when(b.bMethod(any(String.class))
        .thenReturn("yo");

     impl.mainMethod();

    verify(a, times(1)).aMethod(argumentCaptor.capture());
    // fails that 0 times mock was invoked 
   }   

}
Tech Guy
  • 21
  • 2

2 Answers2

0

As I can see it you are mocking Impl but you should instantiate it if you want mainMethod invoke your static methods. Also, are you initializing argumentCaptor somewhere in your code?

Mauricio Mora
  • 749
  • 6
  • 13
  • You're right and partially that mistake happened because I always used `@InjectMock` and `@Mock` annotations. Few questions 1. Can I use this with static members? In my testing it does not work. 2. Is there any better way than setting it or a getter method like getA(), and then mock getA() and then I use getA() in Impl to refer A. 3. Could I mix Mockito and PowerMockito `when`. – Tech Guy Apr 27 '19 at 15:17
  • 1. I think you should, why do you say it's not working? 2. Check out Andrew S answer's here -> https://stackoverflow.com/questions/48691837/how-do-i-mock-a-private-field-using-powermockito seems to be a similar scenario – Mauricio Mora Apr 29 '19 at 15:13
0

I'd like to suggest using Mockito for most testing mocks, and using PowerMockito only when dealing with some static methods. With slight changes, your test code worked ok:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Utils.class })
public class ImplTest {

    @Mock
    A a;

    @Mock
    B b;

    @Captor
    ArgumentCaptor<String> argumentCaptor;

    @BeforeClass
    static public void setUp() {
        PowerMockito.mockStatic(Utils.class);
        Mockito.when(Utils.SomeMethod()).thenReturn("test"); // works
    }

    Impl impl;

    @Before
    public void before() {
        Impl.setA(a);
        Impl.setB(b);

        impl = new Impl();
    }

    @Test
    public void test() {
       Mockito
            .when(a.aMethod(Matchers.any(String.class)))
            .thenReturn("hmmm");

       Mockito
            .when(b.bMethod(Matchers.any(String.class)))
            .thenReturn("yo");

      impl.mainMethod();

      Mockito.verify(a, Mockito.times(1)).aMethod(argumentCaptor.capture());
      Assert.assertEquals("foo", argumentCaptor.getValue());

      Mockito.verify(b, Mockito.times(1)).bMethod(argumentCaptor.capture());
      Assert.assertEquals("bar", argumentCaptor.getValue());
    }

}

Please notice that if A and B are defined as static, they should be injected into the class, not into individual instance(s).

@InjectMocks will not work in this context, since it requires a different Runner. Please have a look at this other article Difference between @Mock and @InjectMocks

Jose Tepedino
  • 1,524
  • 15
  • 18