我需要测试编写一个测试以下行的JUnit测试:
CSVRecord csvRecord = csvReader.readCsv(filename);
来自org.apache.commons.csv的CSVRecord
是最后一堂课。如果我尝试使用EasyMock进行测试,我会收到以下错误:
java.lang.IllegalArgumentException: Cannot subclass final class pathname.FinalClass
at org.easymock.cglib.proxy.Enhancer.generateClass(Enhancer.java:565)
at org.easymock.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at ...
所以我需要从CSVRecord
分离“最终”修饰符。我用javassist尝试过这个。但是,我遇到了一个错误。看看这个简约的例子:
public class MyTestClass extends EasyMockSupport {
@Mock
private MockedClass mockedClass;
@TestSubject
private MyClass classUnderTest = new AmountConverter();
@Test
public void testName() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get(FinalClass.class.getName());
ctClass.defrost();
removeFinal(ctClass);
FinalClass finalClass = (FinalClass) EasyMock.createMock(ctClass.toClass());
expect(mockedClass.foo()).andReturn(finalClass);
replayAll();
classUnderTest.foo();
}
static void removeFinal(CtClass clazz) throws Exception {
int modifiers = clazz.getModifiers();
if(Modifier.isFinal(modifiers)) {
System.out.println("Removing Final");
int notFinalModifier = Modifier.clear(modifiers, Modifier.FINAL);
clazz.setModifiers(notFinalModifier);
}
}
}
与
public class MyClass {
@Inject
private MockedClass mockedClass;
public void foo() {
mockedClass.foo();
}
class MockedClass {
FinalClass foo() {
return null;
}
}
}
并在其自己的类文件中
public final class FinalClass {
}
我收到以下错误
javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "pathname/FinalClass"
at javassist.ClassPool.toClass(ClassPool.java:1099)
at javassist.ClassPool.toClass(ClassPool.java:1042)
at javassist.ClassPool.toClass(ClassPool.java:1000)
at javassist.CtClass.toClass(CtClass.java:1224)
...
答案 0 :(得分:2)
您不能以这种方式更改已加载类的定义。
问题是构造FinalClass.class.getName()
或更具体的类文本FinalClass.class
已经加载了类来生成关联的Class
对象,加载类的运行时表示
假设您之前没有以任何其他方式使用该类,您只需将代码更改为
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("qualified.name.of.FinalClass");
ctClass.defrost();
removeFinal(ctClass);
FinalClass finalClass = (FinalClass) EasyMock.createMock(ctClass.toClass());
在创建运行时表示之前更改类的定义。
答案 1 :(得分:0)
我认为最好使用替代EasyMock而不是玩Javassist。
您可以使用支持模拟最终课程的Mockito 2:Mock the unmockable: opt-in mocking of final classes/methods
另一种选择是使用PowerMock:https://github.com/powermock/powermock/wiki/MockFinal