使用PowerMock,Mockito和TestNG模拟公共方法中使用的私有方法

时间:2012-05-09 22:24:42

标签: java testng mockito powermock

我想为我所拥有的课程编写单元测试。这个类有一个公共方法,在public方法中,在同一个类中调用私有方法。我想模拟对这些私有方法的调用。这个类与此类似:

public class SomeClass {
    public int somePublicMethod(int num) {
        int num2 = somePrivateMethod1(num);
        int num3 = somePrivateMethod2(num);

        return num2 + num3;
    }

    private int somePrivateMethod1(int num) {
        return 2*num;
    }

    private int somePrivateMethod2(int num) {
        return 3*num;
    }
}

对于我的单元测试,我试图将PowerMock与Mockito和TestNG一起使用。这是我尝试测试somePublicMethod:

的测试
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.spy;

import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.Assert;
import org.testng.annotations.Test;

@PrepareForTest(SomeClass.class)
public class SomeClassTest {

    @Test
    public void testSomePublicMethod() throws Exception {
        int num = 4;        

        SomeClass someClassSpy = spy(new SomeClass());

        doReturn(8).when(someClassSpy, "somePrivateMethod1", num);
        doReturn(12).when(someClassSpy, "somePrivateMethod2", num);

        int result = someClassSpy.somePublicMethod(num);

        Assert.assertEquals(result, 20);
    }
}

当我运行此测试时,我得到一个异常和一些提示:

FAILED: testSomePublicMethod
org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:31)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!

我在网上看过一些例子,但我没有找到一个专门用Mockito和TestNG的PowerMock来做我想做的事。有人可以给我一些关于我能做些什么不同的指示吗?

3 个答案:

答案 0 :(得分:5)

我不认为这是PowerMock的问题。它看起来应该工作得很好。我想知道TestNG与PowerMock交互是否存在问题?

我没有使用TestNG的经验,所以我尝试在JUnit中运行该类。 SomeClass原样保留,SomeClassTest最低限度修改为使用JUnit:

import static org.powermock.api.mockito.PowerMockito.*;

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

@RunWith(PowerMockRunner.class)
@PrepareForTest(SomeClass.class)
public class SomeClassTest {

    @Test
    public void testSomePublicMethod() throws Exception {
        final int num = 4;

        final SomeClass someClassSpy = spy(new SomeClass());

        doReturn(8).when(someClassSpy, "somePrivateMethod1", num);
        doReturn(12).when(someClassSpy, "somePrivateMethod2", num);

        final int result = someClassSpy.somePublicMethod(num);

        Assert.assertEquals(result, 20);
    }
}

测试通过。

您是否需要使用PowerMockRunner.class或类似的注释指定@RunWIth,与JUnit一样?如果我删除该注释,我会收到您发布的相同错误消息。

修改

根据此链接: http://code.google.com/p/powermock/wiki/TestNG_usage

您需要告诉TestNG使用PowerMock对象工厂。要以编程方式执行此操作,请将以下方法添加到测试类中:

@ObjectFactory
public IObjectFactory getObjectFactory() {
    return new org.powermock.modules.testng.PowerMockObjectFactory();
}

或者为了安全起见,您还可以从PowerMockTestCase扩展:

@PrepareForTest(SomeClass.class)
public class SomeClassTest extends PowerMockTestCase {
   //...
}

答案 1 :(得分:1)

你不能这样做。你尝试过使用反射吗?

通过使用反射,您可以通过模拟调用方法来模拟私有方法,或者更简单:您可以将其更改为public temporary,然后在测试之后(可能在tearDown中) - 您可以将其更改回private。 / p>

希望得到这个帮助。

答案 2 :(得分:0)

我认为你在这里嘲笑Mockito限制。在类似的情况下,我使用Powermock方法替换,或者将目标方法声明为protected并在构造测试的类实例时覆盖它。 希望有所帮助。