Sar*_*all 6 java junit mockito powermock
我想避免模拟类的getClass()方法,但似乎无法找到它的任何方法.我正在尝试测试一个将HashMap中的对象类类型存储到以后要使用的特定方法的类.一个简短的例子是:
public class ClassToTest {
/** Map that will be populated with objects during constructor */
private Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
ClassToTest() {
/* Loop through methods in ClassToTest and if they return a boolean and
take in an InterfaceA parameter then add them to map */
}
public void testMethod(InterfaceA obj) {
final Method method = map.get(obj.getClass());
boolean ok;
if (method != null) {
ok = (Boolean) method.invoke(this, obj);
}
if (ok) {
obj.run();
}
}
public boolean isSafeClassA(final ClassA obj) {
// Work out if safe to run and then return true/false
}
public boolean isSafeClassB(final ClassB obj) {
// Work out if safe to run and then return true/fals
}
}
public interface InterfaceA {
void run()
}
public class ClassA implements InterfaceA {
public void run() {
// implements method here
}
}
public class ClassB implements InterfaceA {
public void run() {
// implements method here
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有一个看起来像这样的JUnit测试:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassA.class})
public class ClassToTestTest {
private final ClassToTest tester = new ClassToTest();
@Test
public void test() {
MockGateway.MOCK_GET_CLASS_METHOD = true;
final ClassA classA = spy(new ClassA());
doReturn(ClassA.class).when(classA).getClass();
MockGateway.MOCK_GET_CLASS_METHOD = false;
tester.testMethod(classA);
verify(classA).run();
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是虽然在test()方法中有classA.getClass(); 将返回ClassA,一旦在测试者的testMethod()方法内,它仍然返回ClassA $ EnhancerByMockitoWithCGLIB $ ...类,因此我的对象有用将始终为null.
有什么方法可以绕过嘲笑课程或我需要做些什么来解决这个问题?
提前致谢.
您的问题实际上是getClass为final中Object,所以你不能存根的Mockito它.我想不出一个好方法.您可以考虑一种可能性.
编写一个具有单个方法的实用程序类
public Class getClass(Object o){
return o.getClass();
}
Run Code Online (Sandbox Code Playgroud)
并重构您正在测试的类,以便它使用此实用程序类的对象,而不是getClass()直接调用.然后,可以使用特殊的包私有构造函数或使用setter方法注入实用程序对象.
public class ClassToTest{
private UtilityWithGetClass utility;
private Map<Class<?>, Object> map = new HashMap<Class<?>, Object>();
public ClassToTest() {
this(new UtilityWithGetClass());
}
ClassToTest(UtilityWithGetClass utility){
this.utility = utility;
// Populate map here
}
// more stuff here
}
Run Code Online (Sandbox Code Playgroud)
现在,在您的测试中,模拟对象和存根getClass.将模拟注入您正在测试的类中.
哇,让这段代码可测试真是令人头疼。主要问题是您不能将模拟对象用作key对 的调用中的对象map.get(obj.getClass()),并且您正在尝试invoke()潜在地模拟对象以进行测试。我必须重构您的测试类,以便我们可以模拟功能/行为并能够验证其行为。
因此,这是要使用成员变量进行测试的新实现,将各个功能部分解耦并由测试类注入
public class ClassToTest {
MethodStore methodStore;
MethodInvoker methodInvoker;
ClassToInvoke classToInvoke;
ObjectRunner objectRunner;
public void testMethod(InterfaceA obj) throws Exception {
Method method = methodStore.getMethod(obj);
boolean ok = false;
if (method != null) {
ok = methodInvoker.invoke(method, classToInvoke, obj);
}
if (ok) {
objectRunner.run(obj);
}
}
public void setMethodStore(MethodStore methodStore) {
this.methodStore = methodStore;
}
public void setMethodInvoker(MethodInvoker methodInvoker) {
this.methodInvoker = methodInvoker;
}
public void setObjectRunner(ObjectRunner objectRunner) {
this.objectRunner = objectRunner;
}
public void setClassToInvoke(ClassToInvoke classToInvoke) {
this.classToInvoke = classToInvoke;
}
}
Run Code Online (Sandbox Code Playgroud)
这是不再需要 PowerMock 的测试类,因为它无法模拟 Method 类。它只是返回一个 NullPointerException。
public class MyTest {
@Test
public void test() throws Exception {
ClassToTest classToTest = new ClassToTest();
ClassA inputA = new ClassA();
// trying to use powermock here just returns a NullPointerException
// final Method mockMethod = PowerMockito.mock(Method.class);
Method mockMethod = (new ClassToInvoke()).getClass().getMethod("someMethod"); // a real Method instance
// regular mockito for mocking behaviour
ClassToInvoke mockClassToInvoke = mock(ClassToInvoke.class);
classToTest.setClassToInvoke(mockClassToInvoke);
MethodStore mockMethodStore = mock(MethodStore.class);
classToTest.setMethodStore(mockMethodStore);
when(mockMethodStore.getMethod(inputA)).thenReturn(mockMethod);
MethodInvoker mockMethodInvoker = mock(MethodInvoker.class);
classToTest.setMethodInvoker(mockMethodInvoker);
when(mockMethodInvoker.invoke(mockMethod,mockClassToInvoke, inputA)).thenReturn(Boolean.TRUE);
ObjectRunner mockObjectRunner = mock(ObjectRunner.class);
classToTest.setObjectRunner(mockObjectRunner);
// execute test method
classToTest.testMethod(inputA);
verify(mockObjectRunner).run(inputA);
}
}
Run Code Online (Sandbox Code Playgroud)
您需要的额外课程如下
public class ClassToInvoke {
public void someMethod() {};
}
public class ClassA implements InterfaceA {
@Override
public void run() {
// do something
}
}
public class ClassToInvoke {
public void someMethod() {};
}
public class MethodInvoker {
public Boolean invoke(Method method, Object obj, InterfaceA a) throws Exception {
return (Boolean) method.invoke(obj, a);
}
}
public class MethodStore {
Map<Class<?>, Method> map = new HashMap<Class<?>, Method>();
public Method getMethod(InterfaceA obj) {
return map.get(obj);
}
}
Run Code Online (Sandbox Code Playgroud)
将所有这些放入您的 IDE 中,它将通过绿色条...哇哦!
| 归档时间: |
|
| 查看次数: |
5125 次 |
| 最近记录: |