use mock class to setup diagnose

This commit is contained in:
金戟 2021-02-19 13:43:55 +08:00
parent 65cc631d39
commit 82d87f3447
7 changed files with 51 additions and 33 deletions

View File

@ -94,7 +94,7 @@ public class MockClassHandler extends BaseClassWithContextHandler {
// must get label before method description changed
ImmutablePair<LabelNode, LabelNode> labels = getStartAndEndLabel(mn);
mn.desc = MethodUtil.addParameterAtBegin(mn.desc, targetClassName);
int parameterOffset = MethodUtil.isStaticMethod(mn) ? 0 : 1;
int parameterOffset = MethodUtil.isStatic(mn) ? 0 : 1;
mn.localVariables.add(parameterOffset, new LocalVariableNode("__self", targetClassName, null,
labels.left, labels.right, parameterOffset));
for (int i = parameterOffset + 1; i < mn.localVariables.size(); i++) {
@ -114,7 +114,7 @@ public class MockClassHandler extends BaseClassWithContextHandler {
}
private ImmutablePair<LabelNode, LabelNode> getStartAndEndLabel(MethodNode mn) {
if (MethodUtil.isStaticMethod(mn)) {
if (MethodUtil.isStatic(mn)) {
LabelNode startLabel = null, endLabel = null;
for (AbstractInsnNode n = mn.instructions.getFirst(); n != null; n = n.getNext()) {
if (n instanceof LabelNode) {
@ -251,7 +251,7 @@ public class MockClassHandler extends BaseClassWithContextHandler {
int size = types.size();
il.add(getIntInsn(size));
il.add(new TypeInsnNode(ANEWARRAY, ClassUtil.CLASS_OBJECT));
int parameterOffset = MethodUtil.isStaticMethod(mn) ? 0 : 1;
int parameterOffset = MethodUtil.isStatic(mn) ? 0 : 1;
for (int i = 0; i < size; i++) {
il.add(new InsnNode(DUP));
il.add(getIntInsn(i));

View File

@ -22,6 +22,8 @@ public class TestClassHandler extends BaseClassWithContextHandler {
private static final String DESC_METHOD_CLEAN = "()V";
private static final String THIS = "this";
private int testCaseCount = 0;
private final Framework[] frameworkClasses = new Framework[] {
new JUnit4Framework(),
new JUnit5Framework(),
@ -51,6 +53,7 @@ public class TestClassHandler extends BaseClassWithContextHandler {
handleTestableUtil(mn);
handleTestCaseMethod(mn, framework);
}
LogUtil.diagnose(String.format(" Found %d test cases", testCaseCount));
}
private Framework checkFramework(ClassNode cn) {
@ -96,7 +99,9 @@ public class TestClassHandler extends BaseClassWithContextHandler {
private void handleTestCaseMethod(MethodNode mn, Framework framework) {
TestCaseMethodType type = framework.checkMethodType(mn);
if (type.equals(TestCaseMethodType.TEST)) {
LogUtil.verbose(String.format(" Test case \"%s\"", mn.name));
injectMockContextInit(mn);
testCaseCount++;
} else if (type.equals(TestCaseMethodType.AFTER_TEST)) {
injectMockContextClean(mn);
}

View File

@ -8,7 +8,6 @@ import com.alibaba.testable.agent.util.ClassUtil;
import com.alibaba.testable.agent.util.DiagnoseUtil;
import com.alibaba.testable.agent.util.MethodUtil;
import com.alibaba.testable.core.util.LogUtil;
import com.alibaba.testable.core.util.MockAssociationUtil;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
@ -18,7 +17,7 @@ import java.util.ArrayList;
import java.util.List;
import static com.alibaba.testable.agent.util.ClassUtil.toDotSeparateFullClassName;
import static com.alibaba.testable.agent.util.MethodUtil.isStaticMethod;
import static com.alibaba.testable.agent.util.MethodUtil.isStatic;
import static com.alibaba.testable.core.constant.ConstPool.CONSTRUCTOR;
public class MockClassParser {
@ -50,11 +49,6 @@ public class MockClassParser {
* @return found annotation or not
*/
public boolean isMockClass(String className) {
return MockAssociationUtil.mockToTests.containsKey(ClassUtil.toDotSeparatedName(className)) ||
hasMockMethod(className);
}
private boolean hasMockMethod(String className) {
ClassNode cn = ClassUtil.getClassNode(className);
if (cn == null) {
return false;
@ -120,7 +114,7 @@ public class MockClassParser {
private MethodInfo getMethodInfo(MethodNode mn, AnnotationNode an, String targetMethod) {
Type targetType = AnnotationUtil.getAnnotationParameter(an, ConstPool.FIELD_TARGET_CLASS, null, Type.class);
boolean isStatic = isStaticMethod(mn);
boolean isStatic = isStatic(mn);
if (targetType == null) {
// "targetClass" unset, use first parameter as target class type
ImmutablePair<String, String> methodDescPair = extractFirstParameter(mn.desc);
@ -138,7 +132,7 @@ public class MockClassParser {
private void addMockConstructor(List<MethodInfo> methodInfos, ClassNode cn, MethodNode mn) {
String sourceClassName = ClassUtil.getSourceClassName(cn.name);
methodInfos.add(new MethodInfo(sourceClassName, CONSTRUCTOR, mn.desc, mn.name, mn.desc, isStaticMethod(mn)));
methodInfos.add(new MethodInfo(sourceClassName, CONSTRUCTOR, mn.desc, mn.name, mn.desc, isStatic(mn)));
}
/**

View File

@ -106,7 +106,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
}
private String foundMockForSourceClass(String className) {
String mockClass = readMockWithAnnotationAsSourceClass(className);
String mockClass = lookForMockWithAnnotationAsSourceClass(className);
if (mockClass != null) {
return mockClass;
}
@ -114,10 +114,23 @@ public class TestableClassTransformer implements ClassFileTransformer {
}
private String foundMockForTestClass(String className) {
String mockClass = readMockWithAnnotationAndInnerClassAsTestClass(className);
ClassNode cn = ClassUtil.getClassNode(className);
if (cn == null) {
return null;
}
String mockClass = lookForMockWithAnnotationAsTestClass(cn);
if (mockClass != null) {
return mockClass;
}
mockClass = lookForInnerMockClass(cn);
if (mockClass != null) {
return mockClass;
}
return lookForOuterMockClass(className);
}
private String lookForOuterMockClass(String className) {
String mockClass;
mockClass = ClassUtil.getMockClassName(ClassUtil.getSourceClassName(className));
if (mockClassParser.isMockClass(mockClass)) {
return mockClass;
@ -160,7 +173,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
* @param className class that need to explore
* @return name of mock class, null for not found
*/
private String readMockWithAnnotationAsSourceClass(String className) {
private String lookForMockWithAnnotationAsSourceClass(String className) {
ClassNode cn = ClassUtil.getClassNode(className);
if (cn == null) {
return null;
@ -169,35 +182,40 @@ public class TestableClassTransformer implements ClassFileTransformer {
}
/**
* Read @MockWith annotation upon class and inner class "Mock" to fetch mock class
* Read inner class "Mock" to fetch mock class
*
* @param className class that need to explore
* @param cn class that need to explore
* @return name of mock class, null for not found
*/
private String readMockWithAnnotationAndInnerClassAsTestClass(String className) {
ClassNode cn = ClassUtil.getClassNode(className);
if (cn == null) {
return null;
}
// look for MockWith annotation
String mockClassName = parseMockWithAnnotation(cn, ClassType.TestClass);
if (mockClassName != null) {
MockAssociationUtil.mockToTests.get(mockClassName).add(ClassUtil.toDotSeparateFullClassName(className));
return ClassUtil.toSlashSeparatedName(mockClassName);
}
// look for Mock inner class
private String lookForInnerMockClass(ClassNode cn) {
for (InnerClassNode ic : cn.innerClasses) {
if ((ic.access & ACC_PUBLIC) != 0 && ic.name.equals(getInnerMockClassName(className))) {
if ((ic.access & ACC_PUBLIC) != 0 && ic.name.equals(getInnerMockClassName(cn.name)) &&
mockClassParser.isMockClass(ic.name)) {
if ((ic.access & ACC_STATIC) != 0) {
return ic.name;
} else {
LogUtil.warn(String.format("Mock class in \"%s\" is not static", className));
LogUtil.warn(String.format("Mock class in \"%s\" is not declared as static", cn.name));
}
}
}
return null;
}
/**
* Read @MockWith annotation upon class to fetch mock class
*
* @param cn class that need to explore
* @return name of mock class, null for not found
*/
private String lookForMockWithAnnotationAsTestClass(ClassNode cn) {
String mockClassName = parseMockWithAnnotation(cn, ClassType.TestClass);
if (mockClassName != null) {
MockAssociationUtil.mockToTests.get(mockClassName).add(ClassUtil.toDotSeparateFullClassName(cn.name));
return ClassUtil.toSlashSeparatedName(mockClassName);
}
return null;
}
/**
* Get mock class from @MockWith annotation
*

View File

@ -15,7 +15,7 @@ public class MethodUtil {
* @param mn method to check
* @return is static or not
*/
public static boolean isStaticMethod(MethodNode mn) {
public static boolean isStatic(MethodNode mn) {
return (mn.access & ACC_STATIC) != 0;
}

View File

@ -18,6 +18,7 @@ public @interface MockWith {
/**
* explicitly specify mock class
* @note this parameter will become mandatory in v0.6
* @return type of mock class
*/
Class<?> value() default NullType.class;

View File

@ -46,7 +46,7 @@ public class LogUtil {
public static void warn(String msg, Object... args) {
if (currentLogLevel.level >= LogLevel.LEVEL_WARN.level) {
System.out.println(String.format("[WARN] " + msg, args));
System.err.println(String.format("[WARN] " + msg, args));
}
}