alibaba / testable-mock

换种思路写Mock,让单元测试更简单
https://alibaba.github.io/testable-mock/
MIT License
1.83k stars 310 forks source link

scope=ASSOCIATED时报错,Illegal class name "" #177

Closed VicDelacroix closed 2 years ago

VicDelacroix commented 3 years ago

JDK11,win64,Idea,JUnit4 testable version 0.6.7

方法签名 public int insert(ClassA a, ClassB b, ClassC c)

错误堆栈没看到太多的有用信息,去掉ASSOCIATED后正常 java.lang.ClassFormatError: Illegal class name "" in class file xxxTest$Mock

at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1017)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:800)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:698)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:621)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:579)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
linfan commented 3 years ago

估计是原始代码恰好有某些特殊的字节码序列,导致Testable修改后的字节码引用了名称为空的类。 这种情况没有现场凭空不太好猜测,初步看起来比较像是Mock类里的代码导致的,能将insert这个Mock方法里的代码脱敏贴出来吗?

VicDelacroix commented 3 years ago

@linfan 忘了有开源版的了,定位问题应该够了 https://github.com/ctripcorp/dal com.ctrip.platform.dal.dao.DalTableDao#insert(DalHints hints, KeyHolder keyHolder, T daoPojo)

linfan commented 3 years ago

可以的,我这周内抽空复现一下~

linfan commented 3 years ago

@VicDelacroix 我尝试写了一个包含DalTableDao#insert调用的方法,并在单元测试中对DalTableDao#insert方法进行Mock,但并未复现问题。 能否帮忙提供一个可复现上述问题的代码示例呢(简单的测试用例和Mock定义即可)?

VicDelacroix commented 3 years ago

@linfan 有可能和CGLIB有关吗,调用被mock方法的方法由CGLIB处理过,功能类似Spring的@Transactional

public class TestedService implements ApplicationContextAware { private TDao dao;

    @Override
    public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
        dao= applicationContext.getBean(TDao .class);
    }

    @DalTransactional
    public Object tested(Object args) {
            dao.insert(new T());
    }

}

public class TDao { private DalTableDao client = new DalTableDao<>(new DalDefaultJpaParser<>(T.class));

    public int insert(DalHints hints, KeyHolder keyHolder, TdaoPojo) throws SQLException {
    if (null == daoPojo) {
        return 0;
    }
    hints = DalHints.createIfAbsent(hints);
    return client.insert(hints, keyHolder, daoPojo);
}

}

linfan commented 3 years ago

有这个可能,CGLIB也会对字节码进行修改,两边在某种情况下会发生巧合冲突。

对于Testable来说,使用MockScope.ASSOCIATED只是会在调用Mock方法体之前增加一次来源检查,没有动态生成类名,应该不会直接造成“Illegal class name "" ”错误。在没有现场或可重现代码的情况下,目前的线索依然不太有用。