Mocked private method with PowerMock, but underlying method still gets called

前端 未结 5 1220
暗喜
暗喜 2020-12-14 07:50

I am trying to mock out a private method that is making a JNDI call. When that method gets called from a unit test, it throws an exception^. I would like to mock-out that me

相关标签:
5条回答
  • 2020-12-14 07:58

    when you use spy to construct a mock object, its a real half backed object. My guess would be to get rid of spy. Work on pure mock object.

    0 讨论(0)
  • 2020-12-14 07:59

    ArtB,

    Are you sure your code doesn't work (or) am i missing something here? I just replaced your method expectation with the following one the way Mike suggested and it works fine:

    PowerMockito.doReturn(true).when(spy, 
                   method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
                    .withArguments(anyString(), anyInt());
    

    I never used Powermockito but used Mockito a lot before.

    0 讨论(0)
  • 2020-12-14 08:03

    ArtB,

    Just pasting the complete code which works fine in my Eclipse IDE. I have only changed the expectation i said in my last post. Good luck.

    import static org.hamcrest.core.Is.is;
    import static org.junit.Assert.assertThat;
    import static org.mockito.Matchers.anyInt;
    import static org.mockito.Matchers.anyString;
    import static org.powermock.api.support.membermodification.MemberMatcher.method;
    
    import java.util.Random;
    
    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;
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(CodeWithPrivateMethod.class)
    public class PowerMock_Test {
    
        static boolean gambleCalled = false; 
    
        @Test(expected = RuntimeException.class)
        public void when_gambling_is_true_then_always_explode() throws Exception {
            CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());
    
    //        PowerMockito.doReturn(true).when(spy, "doTheGamble", anyString(), anyInt());
    
            PowerMockito.doReturn(true).when(spy, 
                   method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
                    .withArguments(anyString(), anyInt());
    
            assertThat( PowerMock_Test.gambleCalled, is(false) );
            spy.meaningfulPublicApi();
            assertThat( PowerMock_Test.gambleCalled, is(false) );
        }
    }
    
    
    class CodeWithPrivateMethod {
    
        public void meaningfulPublicApi() {
            if (doTheGamble("Whatever", 1 << 3)) {
                throw new RuntimeException("boom");
            }
        }
    
        private boolean doTheGamble(String whatever, int binary) {
            Random random = new Random(System.nanoTime());
            boolean gamble = random.nextBoolean();
    
            System.err.println( "\n>>> GAMBLE CALLED <<<\n" );
            PowerMock_Test.gambleCalled = true;
    
            return gamble;
        }
    }   
    
    0 讨论(0)
  • 2020-12-14 08:04

    none of the above worked for me 'cause my private method was void.

    had a setup like:

    public class MainClass {
        public void publicFunction () {
          this.privateFunction(Arg1.class arg1, Arg2.class arg2);
        }
    
        private void privateFunction(Arg1.class arg1, Arg2.class arg2){
           // who cares, I don't want any of this to go off
        }
    
    }
    

    and the only thing that worked was:

    @Test
    public void whocares() throws Exception {
       mainSpy = spy(mockedMainClassInstance);
       PowerMockito.doNothing().when(mainSpy, "privateFunction", mockedArg1, mockedArg2);
       mainSpy.publicFunction(mockedArg0, mockedArg1, mockedArg2);
       verifyPrivate(mainSpy).invoke("privateFunction", mockedArg1, mockedArg2);
    

    }

    and that's when the code in the private function stopped firing

    0 讨论(0)
  • 2020-12-14 08:09

    From the PowerMock Private Method Example:

    @RunWith(PowerMockRunner.class)
    // We prepare PartialMockClass for test because it's final or we need to mock private or static methods
    @PrepareForTest(PartialMockClass.class)
    public class YourTestCase {
    @Test
    public void privatePartialMockingWithPowerMock() {        
        PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass());
    
        // use PowerMockito to set up your expectation
        PowerMockito.doReturn(value).when(classUnderTest, "methodToMock", "parameter1");
    
        // execute your test
        classUnderTest.execute();
    
        // Use PowerMockito.verify() to verify result
        PowerMockito.verifyPrivate(classUnderTest, times(2)).invoke("methodToMock", "parameter1");
    }
    

    So to apply this to your code, I think it might become:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(CodeWithPrivateMethod.class)
    public class PowerMock_Test {
        @Test(expected = RuntimeException.class)
        public void when_gambling_is_true_then_always_explode() throws Exception {
            CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());
    
            PowerMockito.doReturn(true).when(spy, "doTheGamble", anyString(), anyInt());
    
    
    /* 1 */ PowerMockito.verifyPrivate(spy, times(0)).invoke("doTheGamble", anyString(), anyInt());            
            spy.meaningfulPublicApi();
    /* 2 */ PowerMockito.verifyPrivate(spy, times(2)).invoke("doTheGamble", anyString(), anyInt());            
        }
    }
    

    I just coded that in the editor here. No tests have actually been run, and no bugs have been harmed in the crafting of this code.

    0 讨论(0)
提交回复
热议问题