我正在使用Mockito 1.9.5,PowerMock 1.5.1,JUnit 4.11和Spring 3.1.4.RELEASE。我正在尝试编写一个JUnit测试,其中我想模拟一个什么都不做的私有方法。私有方法签名是
public class MyService
{
…
private void myMethod(byte[] data, UserFile userFile, User user)
{
在我的JUnit测试中,我有
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
@PrepareForTest(MyServiceImpl.class)
public class MyServiceIT
{
@Rule
public PowerMockRule rule = new PowerMockRule();
@Autowired
private MyService m_mySvc;
private MyService m_mySvcSpy;
@Before
public final void setup() throws Exception
{
m_mySvcSpy = PowerMockito.spy(m_mySvc);
PowerMockito.doNothing().when(m_mySvcSpy, “myMethod”, Matchers.any(byte[].class), Matchers.any(UserFile.class), Matchers.any(User.class));
不幸的是,第二行死于异常
testUploadFile(org.mainco.subco.user.service.MyServiceIT) Time elapsed: 12.693 sec <<< ERROR!
org.powermock.reflect.exceptions.MethodNotFoundException:在类org.mainco.subco.user.service.UserFileService $$ EnhancerByMockitoWithCGLIB $$ 4中找不到名称为'myMethod'且参数类型为[null,null,null]的方法e52bc77。 at org.powermock.reflect.internal.WhiteboxImpl.throwExceptionIfMethodWasNotFound(WhiteboxImpl.java:1247) at org.powermock.reflect.internal.WhiteboxImpl.findMethodOrThrowException(WhiteboxImpl.java:985) at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:882) 在org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:713) 在org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:401) 在org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:93) 在org.mainco.subco.user.service.MyServiceIT.setup(UserFileServiceIT.java:42)
使用PowerMockito模拟私有方法的泛型参数的正确方法是什么?
答案 0 :(得分:1)
我还没有对它进行测试,但我认为找不到私有方法的原因是它在Spring提供的对象中不存在 MyService
界面。此对象是代理,生成的类的实例,不扩展MyServiceImpl
;所以,其中没有private myMethod(...)
。
为了避免这个问题,测试应该不使用Spring。而是直接在MyServiceImpl
方法中实例化setup()
。如果测试需要其他依赖项注入m_mySvc
,那么为那些创建模拟并让PowerMock注入它们。
答案 1 :(得分:1)
在我的情况下,我希望私有方法能够&#34;返回&#34;什么,所以这就是我做的事情
MyTestClass spyInstance = spy(MyTestClass.getNewInstance());
MyGenericClass obj = mock(MyGenericClass.class);
doReturn(obj).when(spyInstance,method(MyTestClass.class,"privateMethod",
String.class,HashMap.class,Class.class)).
withArguments("624",null,MyGenericClass.class);`
我的私人方法是......
private <T> T privateMethod(String str,HashMap<String,String> map,Class<T> c)
答案 2 :(得分:0)
我猜你的测试是用SpringJUnit4ClassRunner
注释的。在这种情况下,您必须使用PowerMockRule
:
public class MyServiceTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
...
此外,你正在使用powermock来解释MyService
的方法。因此,您必须使用@PrepareForTest
注释测试类:
...
@PrepareForTest(MyServiceImpl.class)
public class MyServiceTest {
...
完整代码:
@PrepareForTest(MyServiceImpl.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Autowired
private MyService service;
private MyService spy;
@Before
public final void setup() throws Exception {
spy = PowerMockito.spy(service);
PowerMockito.doNothing().when(spy,
"myMethod",
Matchers.any(byte[].class),
Matchers.any(UserFile.class),
Matchers.any(User.class));
}
...
}
答案 3 :(得分:0)
你的问题的前提似乎暗示你违反了Single Responsibility Principle (SRP);如果你需要测试私有方法,并且为了做到这一点,你需要将东西注入其中,你应该考虑将它移到另一个服务。
我建议您执行以下操作:
public class MyService implements IService { // I know it's not a strong convention in
// the Java world, but I'm primarily a C#
// guy, so I tend to give any interface a
// name that starts with captital "I"
public MyService(IDependencyOne dep1, IDependencyTwo dep2) {
// ...
}
public Stuff getTheStuffThatAnIServiceGets() {
// your previously private method was used here before
// Now, it's instead a method defined on the IDependencyTwo interface,
// so you have it available as _dep2.myMethod(...)
}
}
public class OtherService implements IDependencyTwo {
public void myMethod(/* possibly some arguments... */) {
// ...
}
}
通过这种分离,你可以在测试IDependencyTwo
时注入一些嘲弄先前私有方法(只是模拟MyService
)的行为,同样你可以模拟你需要注入的任何内容通过模拟和注入IDependencyTwo
的依赖关系进入以前的私有方法。
答案 4 :(得分:0)
因为你看到了这个例外:
org.powermock.reflect.exceptions.MethodNotFoundException: No method found with name ‘myMethod’ with parameter types: [ null, null, null ] in class
您可以尝试使用mockito的isNull匹配器(并且可能使用某种类型转换器)吗?
换句话说,你改为使用
PowerMockito.doNothing().when(m_mySvcSpy, "myMethod", Matchers.isNull(byte[].class), Matchers.isNull(UserFile.class), Matchers.isNull(User.class));
顺便说一句,你可以static import Matchers.isNull
,这样你就可以简单地使用isNull
代替Matchers.isNull
答案 5 :(得分:0)
我继续使用“压制”......
suppress(method(MyServiceImpl.class, “myMethod”));