mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-27 12:51:00 +08:00
use mock class to setup diagnose
This commit is contained in:
parent
65cc631d39
commit
82d87f3447
@ -94,7 +94,7 @@ public class MockClassHandler extends BaseClassWithContextHandler {
|
|||||||
// must get label before method description changed
|
// must get label before method description changed
|
||||||
ImmutablePair<LabelNode, LabelNode> labels = getStartAndEndLabel(mn);
|
ImmutablePair<LabelNode, LabelNode> labels = getStartAndEndLabel(mn);
|
||||||
mn.desc = MethodUtil.addParameterAtBegin(mn.desc, targetClassName);
|
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,
|
mn.localVariables.add(parameterOffset, new LocalVariableNode("__self", targetClassName, null,
|
||||||
labels.left, labels.right, parameterOffset));
|
labels.left, labels.right, parameterOffset));
|
||||||
for (int i = parameterOffset + 1; i < mn.localVariables.size(); i++) {
|
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) {
|
private ImmutablePair<LabelNode, LabelNode> getStartAndEndLabel(MethodNode mn) {
|
||||||
if (MethodUtil.isStaticMethod(mn)) {
|
if (MethodUtil.isStatic(mn)) {
|
||||||
LabelNode startLabel = null, endLabel = null;
|
LabelNode startLabel = null, endLabel = null;
|
||||||
for (AbstractInsnNode n = mn.instructions.getFirst(); n != null; n = n.getNext()) {
|
for (AbstractInsnNode n = mn.instructions.getFirst(); n != null; n = n.getNext()) {
|
||||||
if (n instanceof LabelNode) {
|
if (n instanceof LabelNode) {
|
||||||
@ -251,7 +251,7 @@ public class MockClassHandler extends BaseClassWithContextHandler {
|
|||||||
int size = types.size();
|
int size = types.size();
|
||||||
il.add(getIntInsn(size));
|
il.add(getIntInsn(size));
|
||||||
il.add(new TypeInsnNode(ANEWARRAY, ClassUtil.CLASS_OBJECT));
|
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++) {
|
for (int i = 0; i < size; i++) {
|
||||||
il.add(new InsnNode(DUP));
|
il.add(new InsnNode(DUP));
|
||||||
il.add(getIntInsn(i));
|
il.add(getIntInsn(i));
|
||||||
|
@ -22,6 +22,8 @@ public class TestClassHandler extends BaseClassWithContextHandler {
|
|||||||
private static final String DESC_METHOD_CLEAN = "()V";
|
private static final String DESC_METHOD_CLEAN = "()V";
|
||||||
private static final String THIS = "this";
|
private static final String THIS = "this";
|
||||||
|
|
||||||
|
private int testCaseCount = 0;
|
||||||
|
|
||||||
private final Framework[] frameworkClasses = new Framework[] {
|
private final Framework[] frameworkClasses = new Framework[] {
|
||||||
new JUnit4Framework(),
|
new JUnit4Framework(),
|
||||||
new JUnit5Framework(),
|
new JUnit5Framework(),
|
||||||
@ -51,6 +53,7 @@ public class TestClassHandler extends BaseClassWithContextHandler {
|
|||||||
handleTestableUtil(mn);
|
handleTestableUtil(mn);
|
||||||
handleTestCaseMethod(mn, framework);
|
handleTestCaseMethod(mn, framework);
|
||||||
}
|
}
|
||||||
|
LogUtil.diagnose(String.format(" Found %d test cases", testCaseCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Framework checkFramework(ClassNode cn) {
|
private Framework checkFramework(ClassNode cn) {
|
||||||
@ -96,7 +99,9 @@ public class TestClassHandler extends BaseClassWithContextHandler {
|
|||||||
private void handleTestCaseMethod(MethodNode mn, Framework framework) {
|
private void handleTestCaseMethod(MethodNode mn, Framework framework) {
|
||||||
TestCaseMethodType type = framework.checkMethodType(mn);
|
TestCaseMethodType type = framework.checkMethodType(mn);
|
||||||
if (type.equals(TestCaseMethodType.TEST)) {
|
if (type.equals(TestCaseMethodType.TEST)) {
|
||||||
|
LogUtil.verbose(String.format(" Test case \"%s\"", mn.name));
|
||||||
injectMockContextInit(mn);
|
injectMockContextInit(mn);
|
||||||
|
testCaseCount++;
|
||||||
} else if (type.equals(TestCaseMethodType.AFTER_TEST)) {
|
} else if (type.equals(TestCaseMethodType.AFTER_TEST)) {
|
||||||
injectMockContextClean(mn);
|
injectMockContextClean(mn);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import com.alibaba.testable.agent.util.ClassUtil;
|
|||||||
import com.alibaba.testable.agent.util.DiagnoseUtil;
|
import com.alibaba.testable.agent.util.DiagnoseUtil;
|
||||||
import com.alibaba.testable.agent.util.MethodUtil;
|
import com.alibaba.testable.agent.util.MethodUtil;
|
||||||
import com.alibaba.testable.core.util.LogUtil;
|
import com.alibaba.testable.core.util.LogUtil;
|
||||||
import com.alibaba.testable.core.util.MockAssociationUtil;
|
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
import org.objectweb.asm.tree.AnnotationNode;
|
import org.objectweb.asm.tree.AnnotationNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
@ -18,7 +17,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.alibaba.testable.agent.util.ClassUtil.toDotSeparateFullClassName;
|
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;
|
import static com.alibaba.testable.core.constant.ConstPool.CONSTRUCTOR;
|
||||||
|
|
||||||
public class MockClassParser {
|
public class MockClassParser {
|
||||||
@ -50,11 +49,6 @@ public class MockClassParser {
|
|||||||
* @return found annotation or not
|
* @return found annotation or not
|
||||||
*/
|
*/
|
||||||
public boolean isMockClass(String className) {
|
public boolean isMockClass(String className) {
|
||||||
return MockAssociationUtil.mockToTests.containsKey(ClassUtil.toDotSeparatedName(className)) ||
|
|
||||||
hasMockMethod(className);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasMockMethod(String className) {
|
|
||||||
ClassNode cn = ClassUtil.getClassNode(className);
|
ClassNode cn = ClassUtil.getClassNode(className);
|
||||||
if (cn == null) {
|
if (cn == null) {
|
||||||
return false;
|
return false;
|
||||||
@ -120,7 +114,7 @@ public class MockClassParser {
|
|||||||
|
|
||||||
private MethodInfo getMethodInfo(MethodNode mn, AnnotationNode an, String targetMethod) {
|
private MethodInfo getMethodInfo(MethodNode mn, AnnotationNode an, String targetMethod) {
|
||||||
Type targetType = AnnotationUtil.getAnnotationParameter(an, ConstPool.FIELD_TARGET_CLASS, null, Type.class);
|
Type targetType = AnnotationUtil.getAnnotationParameter(an, ConstPool.FIELD_TARGET_CLASS, null, Type.class);
|
||||||
boolean isStatic = isStaticMethod(mn);
|
boolean isStatic = isStatic(mn);
|
||||||
if (targetType == null) {
|
if (targetType == null) {
|
||||||
// "targetClass" unset, use first parameter as target class type
|
// "targetClass" unset, use first parameter as target class type
|
||||||
ImmutablePair<String, String> methodDescPair = extractFirstParameter(mn.desc);
|
ImmutablePair<String, String> methodDescPair = extractFirstParameter(mn.desc);
|
||||||
@ -138,7 +132,7 @@ public class MockClassParser {
|
|||||||
|
|
||||||
private void addMockConstructor(List<MethodInfo> methodInfos, ClassNode cn, MethodNode mn) {
|
private void addMockConstructor(List<MethodInfo> methodInfos, ClassNode cn, MethodNode mn) {
|
||||||
String sourceClassName = ClassUtil.getSourceClassName(cn.name);
|
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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +106,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String foundMockForSourceClass(String className) {
|
private String foundMockForSourceClass(String className) {
|
||||||
String mockClass = readMockWithAnnotationAsSourceClass(className);
|
String mockClass = lookForMockWithAnnotationAsSourceClass(className);
|
||||||
if (mockClass != null) {
|
if (mockClass != null) {
|
||||||
return mockClass;
|
return mockClass;
|
||||||
}
|
}
|
||||||
@ -114,10 +114,23 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String foundMockForTestClass(String className) {
|
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) {
|
if (mockClass != null) {
|
||||||
return mockClass;
|
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));
|
mockClass = ClassUtil.getMockClassName(ClassUtil.getSourceClassName(className));
|
||||||
if (mockClassParser.isMockClass(mockClass)) {
|
if (mockClassParser.isMockClass(mockClass)) {
|
||||||
return mockClass;
|
return mockClass;
|
||||||
@ -160,7 +173,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
* @param className class that need to explore
|
* @param className class that need to explore
|
||||||
* @return name of mock class, null for not found
|
* @return name of mock class, null for not found
|
||||||
*/
|
*/
|
||||||
private String readMockWithAnnotationAsSourceClass(String className) {
|
private String lookForMockWithAnnotationAsSourceClass(String className) {
|
||||||
ClassNode cn = ClassUtil.getClassNode(className);
|
ClassNode cn = ClassUtil.getClassNode(className);
|
||||||
if (cn == null) {
|
if (cn == null) {
|
||||||
return 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
|
* @return name of mock class, null for not found
|
||||||
*/
|
*/
|
||||||
private String readMockWithAnnotationAndInnerClassAsTestClass(String className) {
|
private String lookForInnerMockClass(ClassNode cn) {
|
||||||
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
|
|
||||||
for (InnerClassNode ic : cn.innerClasses) {
|
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) {
|
if ((ic.access & ACC_STATIC) != 0) {
|
||||||
return ic.name;
|
return ic.name;
|
||||||
} else {
|
} 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;
|
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
|
* Get mock class from @MockWith annotation
|
||||||
*
|
*
|
||||||
|
@ -15,7 +15,7 @@ public class MethodUtil {
|
|||||||
* @param mn method to check
|
* @param mn method to check
|
||||||
* @return is static or not
|
* @return is static or not
|
||||||
*/
|
*/
|
||||||
public static boolean isStaticMethod(MethodNode mn) {
|
public static boolean isStatic(MethodNode mn) {
|
||||||
return (mn.access & ACC_STATIC) != 0;
|
return (mn.access & ACC_STATIC) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ public @interface MockWith {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* explicitly specify mock class
|
* explicitly specify mock class
|
||||||
|
* @note this parameter will become mandatory in v0.6
|
||||||
* @return type of mock class
|
* @return type of mock class
|
||||||
*/
|
*/
|
||||||
Class<?> value() default NullType.class;
|
Class<?> value() default NullType.class;
|
||||||
|
@ -46,7 +46,7 @@ public class LogUtil {
|
|||||||
|
|
||||||
public static void warn(String msg, Object... args) {
|
public static void warn(String msg, Object... args) {
|
||||||
if (currentLogLevel.level >= LogLevel.LEVEL_WARN.level) {
|
if (currentLogLevel.level >= LogLevel.LEVEL_WARN.level) {
|
||||||
System.out.println(String.format("[WARN] " + msg, args));
|
System.err.println(String.format("[WARN] " + msg, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user