4
public static ResponseBean call(Bean bean) throws Exception {
    // statements...
    IgnoreCall.ignoreMethodCall(bean);
    // statements...

    // return
}

With the code snippet above, is it possible to test the method ignoring invocation of IgnoreCall.ignoreMethod(Bean) without needing to place the entire statement under a boolean condition?

Here's the unit test code snippet:

@RunWith(PowerMockRunner.class)
@PrepareTest
public ClassHelperTest {

    @Test
    public void testCall() throws Excpetion {
        // stubbing...
        ResponseBean responseBean = ClassHelper.call(bean);
        // verify/ies
        // assert/s
    }

}

Notes:

  • Refactoring ClassHelper.call(Bean) should be avoided. Even with a bad OO design, refactoring is costly.
  • Method signature is locked unless another pattern is applicable for replacement.
  • Tried using Mockito.when and PowerMockito.when on the target static method, stubbing didn't work on run-time debug.
David B
  • 3,269
  • 12
  • 48
  • 80
  • 2
    Thing is: **static** is an abnormality in OO design; and as you just noticed: it makes your code much **harder** to test. PowerMock can "fix" that problem; but I would rather recommend you to change your production code. No static calls, no such problems. – GhostCat Dec 09 '16 at 07:30
  • If refactoring was easy, I would have done it by then. Unfortunately with a poor OO design at hand, I'm stuck at this. You speak of `PowerMock can fix that problem`, care to share how? – David B Dec 09 '16 at 10:13
  • Appreciated your answer, but removing the parameters isn't going to be a good approach for me. By any chance a build-pattern would do? – David B Dec 09 '16 at 10:43
  • No worries. Didn't work on the production code but on the snippet I did, worked. Looking back into it, reason why it's not applicable is that `IgnoreCall.ignoreMethodCall(Bean)` has a series of inner static method invocation (out of scope of this question). – David B Dec 16 '16 at 07:17
  • I'll try to open another question mimicking the one in production. I'll give you a post. Sorry was accessing SO using RSS so I didn't received the mandatory notification to award it, though the bounty was deducted on my end. – David B Dec 21 '16 at 06:42

1 Answers1

7

As your comments indicate that changing your production code is not possible, you "simply" have to dive into the static-mocking aspects of PowerMock; as outlined here for example.

Basically you need to enable IgnoreCall for static mocking; and then you make calls to ignoreMethodCall() a no-op.

But as you keep asking: the core problem with your question is the fact that you want to mock out a static method that is void. I have a complete example below, but before that some explanations.

The point is: you call a method for two reasons:

  1. It has a side effect
  2. It returns a value, and maybe, causes a side effect, too

A void method can only be called for side effects. And the thing is: when you do static mocking, then that works on class level.

Meaning: you instruct PowerMock to "prevent" any of the static methods of some class from execution; you simply "erase" the side effects of all those static methods! So, by telling PowerMock to do those static mocks, all void methods are already "gone".

But as said, you might also call methods for their return value. And then is when the when() method of Mockito kicks in. You use that method to say: when that value-returning method is invoked, then do this or that.

Long story short; here is a [mcve] using the elements you asked for:

package ghostcat.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

class IgnoreCall {
  public static void ignoreMethodCall(Object o) {
    System.out.println("SHOULD NOT SHOW UP: " + o);
  }
}

class CuT {
  public static Object call(Object bean) {
    System.out.println("statement1");
    IgnoreCall.ignoreMethodCall(bean);
    System.out.println("statement2");
    return "whatever";
  }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(IgnoreCall.class)
public class PMTest {
  @Test
  public void test() {
    PowerMockito.mockStatic(IgnoreCall.class);
    CuT.call("yeha");
  }
}

As in your example ... there is IgnoreCall; used within that a static method that I just called "call".

This prints:

statement1
statement2

When I go in and comment out

//      PowerMockito.mockStatic(IgnoreCall.class);

It prints:

statement1
SHOULD NOT SHOW UP: yeha
statement2

So, a simple example that should tell you exactly what you need to do.

I worked with eclipse neon, IBM java8 JDK, and simply imported all the JARs from powermock-mockito-junit-1.6.6.zip into my test project.

Community
  • 1
  • 1
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Can't still comprehend why stubbing parameters won't work? Used `Mockito.when` and `PowerMockito.when` and both didn't work accordingly. – David B Dec 09 '16 at 10:42
  • This should be the accepted answer. Did you read the link @GhostCat posted? `PowerMockito.mockStatic(IgnoreCall.class);` and make sure you are using the PowerMocks runner. – David Rawson Dec 15 '16 at 08:51
  • @CyrilHorad I kinda agree with what David says, too. You see, the thing that you intend to do is *documented* in the answer I am linking to. What part is missing for you there? Do you really need people to write up an example especially for you. – GhostCat Dec 15 '16 at 08:56
  • Reason behind not yet accepting is `IgnoreCall.ignoreMethodCall(Bean)` has series of static void method invocations on other class/s. – David B Dec 16 '16 at 03:27