mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-03-23 16:20:26 +08:00
suggest use MockDiagnose to set log level
This commit is contained in:
parent
9eb8682ec0
commit
be53ea2d9c
@ -17,6 +17,7 @@ public class ConstPool {
|
|||||||
public static final String FIELD_TARGET_CLASS = "targetClass";
|
public static final String FIELD_TARGET_CLASS = "targetClass";
|
||||||
|
|
||||||
public static final String MOCK_WITH = "com.alibaba.testable.core.annotation.MockWith";
|
public static final String MOCK_WITH = "com.alibaba.testable.core.annotation.MockWith";
|
||||||
|
public static final String MOCK_DIAGNOSE = "com.alibaba.testable.core.annotation.MockDiagnose";
|
||||||
public static final String MOCK_METHOD = "com.alibaba.testable.core.annotation.MockMethod";
|
public static final String MOCK_METHOD = "com.alibaba.testable.core.annotation.MockMethod";
|
||||||
public static final String MOCK_CONSTRUCTOR = "com.alibaba.testable.core.annotation.MockConstructor";
|
public static final String MOCK_CONSTRUCTOR = "com.alibaba.testable.core.annotation.MockConstructor";
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import com.alibaba.testable.agent.util.ClassUtil;
|
|||||||
import com.alibaba.testable.agent.util.GlobalConfig;
|
import com.alibaba.testable.agent.util.GlobalConfig;
|
||||||
import com.alibaba.testable.agent.util.StringUtil;
|
import com.alibaba.testable.agent.util.StringUtil;
|
||||||
import com.alibaba.testable.core.model.ClassType;
|
import com.alibaba.testable.core.model.ClassType;
|
||||||
import com.alibaba.testable.core.model.MockDiagnose;
|
import com.alibaba.testable.core.model.LogLevel;
|
||||||
import com.alibaba.testable.core.util.LogUtil;
|
import com.alibaba.testable.core.util.LogUtil;
|
||||||
import com.alibaba.testable.core.util.MockContextUtil;
|
import com.alibaba.testable.core.util.MockContextUtil;
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
@ -48,12 +48,11 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
private static final String CLASS_OBJECT = "java/lang/Object";
|
private static final String CLASS_OBJECT = "java/lang/Object";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Just avoid spend time to scan those surely non-user classes
|
* Just avoid spend time to scan those surely non-user classes Should keep these lists as tiny as possible
|
||||||
* Should keep these lists as tiny as possible
|
|
||||||
*/
|
*/
|
||||||
private final String[] WHITELIST_PREFIXES = new String[] { "com/alibaba/testable/demo/" };
|
private final String[] WHITELIST_PREFIXES = new String[] {"com/alibaba/testable/demo/"};
|
||||||
private final String[] BLACKLIST_PREFIXES = new String[] { "jdk/", "java/", "javax/", "com/sun/",
|
private final String[] BLACKLIST_PREFIXES = new String[] {"jdk/", "java/", "javax/", "com/sun/",
|
||||||
"org/apache/maven/", "com/alibaba/testable/", "junit/", "org/junit/", "org/testng/" };
|
"org/apache/maven/", "com/alibaba/testable/", "junit/", "org/junit/", "org/testng/"};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
|
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
@ -103,7 +102,8 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
String dumpFile = StringUtil.joinPath(dumpDir, className.replace(SLASH, DOT).replace(DOLLAR, UNDERLINE) + ".class");
|
String dumpFile = StringUtil.joinPath(dumpDir,
|
||||||
|
className.replace(SLASH, DOT).replace(DOLLAR, UNDERLINE) + ".class");
|
||||||
LogUtil.verbose("Dump class: " + dumpFile);
|
LogUtil.verbose("Dump class: " + dumpFile);
|
||||||
FileOutputStream stream = new FileOutputStream(dumpFile);
|
FileOutputStream stream = new FileOutputStream(dumpFile);
|
||||||
stream.write(bytes);
|
stream.write(bytes);
|
||||||
@ -241,6 +241,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Read @MockWith annotation upon class to fetch mock class
|
* Read @MockWith annotation upon class to fetch mock class
|
||||||
|
*
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
@ -254,6 +255,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Read @MockWith annotation upon class and inner class "Mock" to fetch mock class
|
* Read @MockWith annotation upon class and inner class "Mock" to fetch mock class
|
||||||
|
*
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
@ -283,14 +285,15 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get mock class from @MockWith annotation
|
* Get mock class from @MockWith annotation
|
||||||
|
*
|
||||||
* @param cn class that may have @MockWith annotation
|
* @param cn class that may have @MockWith annotation
|
||||||
* @return mock class name
|
* @return mock class name
|
||||||
*/
|
*/
|
||||||
private String parseMockWithAnnotation(ClassNode cn, ClassType expectedType) {
|
private String parseMockWithAnnotation(ClassNode cn, ClassType expectedType) {
|
||||||
if (cn.visibleAnnotations != null) {
|
if (cn.visibleAnnotations != null) {
|
||||||
for (AnnotationNode an : cn.visibleAnnotations) {
|
for (AnnotationNode an : cn.visibleAnnotations) {
|
||||||
|
setupDiagnose(an);
|
||||||
if (toDotSeparateFullClassName(an.desc).equals(ConstPool.MOCK_WITH)) {
|
if (toDotSeparateFullClassName(an.desc).equals(ConstPool.MOCK_WITH)) {
|
||||||
setupDiagnose(an);
|
|
||||||
ClassType type = AnnotationUtil.getAnnotationParameter(an, FIELD_TREAT_AS, ClassType.GuessByName,
|
ClassType type = AnnotationUtil.getAnnotationParameter(an, FIELD_TREAT_AS, ClassType.GuessByName,
|
||||||
ClassType.class);
|
ClassType.class);
|
||||||
if (isExpectedType(cn.name, type, expectedType)) {
|
if (isExpectedType(cn.name, type, expectedType)) {
|
||||||
@ -316,6 +319,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether any method in specified class has mock-related annotation
|
* Check whether any method in specified class has mock-related annotation
|
||||||
|
*
|
||||||
* @param className class that need to explore
|
* @param className class that need to explore
|
||||||
* @return found annotation or not
|
* @return found annotation or not
|
||||||
*/
|
*/
|
||||||
@ -324,6 +328,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
if (cn == null) {
|
if (cn == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
setupDiagnose(cn);
|
||||||
for (MethodNode mn : cn.methods) {
|
for (MethodNode mn : cn.methods) {
|
||||||
if (mn.visibleAnnotations != null) {
|
if (mn.visibleAnnotations != null) {
|
||||||
for (AnnotationNode an : mn.visibleAnnotations) {
|
for (AnnotationNode an : mn.visibleAnnotations) {
|
||||||
@ -352,11 +357,29 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
return cn;
|
return cn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupDiagnose(ClassNode cn) {
|
||||||
|
if (cn.visibleAnnotations == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (AnnotationNode an : cn.visibleAnnotations) {
|
||||||
|
setupDiagnose(an);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setupDiagnose(AnnotationNode an) {
|
private void setupDiagnose(AnnotationNode an) {
|
||||||
MockDiagnose diagnose = AnnotationUtil.getAnnotationParameter(an, FIELD_DIAGNOSE, null, MockDiagnose.class);
|
if (toDotSeparateFullClassName(an.desc).equals(MOCK_WITH)) {
|
||||||
if (diagnose != null) {
|
setupDianose(an, FIELD_DIAGNOSE);
|
||||||
LogUtil.setLevel(diagnose == MockDiagnose.ENABLE ? LogUtil.LogLevel.LEVEL_DIAGNOSE :
|
}
|
||||||
(diagnose == MockDiagnose.VERBOSE ? LogUtil.LogLevel.LEVEL_VERBOSE : LogUtil.LogLevel.LEVEL_MUTE));
|
if (toDotSeparateFullClassName(an.desc).equals(ConstPool.MOCK_DIAGNOSE)) {
|
||||||
|
setupDianose(an, FIELD_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupDianose(AnnotationNode an, String fieldDiagnose) {
|
||||||
|
LogLevel level = AnnotationUtil.getAnnotationParameter(an, fieldDiagnose, null, LogLevel.class);
|
||||||
|
if (level != null) {
|
||||||
|
LogUtil.setLevel(level == LogLevel.ENABLE ? LogUtil.LogLevel.LEVEL_DIAGNOSE :
|
||||||
|
(level == LogLevel.VERBOSE ? LogUtil.LogLevel.LEVEL_VERBOSE : LogUtil.LogLevel.LEVEL_MUTE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.alibaba.testable.core.annotation;
|
||||||
|
|
||||||
|
import com.alibaba.testable.core.model.LogLevel;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set extra mock parameter to test class
|
||||||
|
*
|
||||||
|
* @author flin
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Documented
|
||||||
|
public @interface MockDiagnose {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switch of mock diagnose information of current test class
|
||||||
|
* @return enable or disable
|
||||||
|
*/
|
||||||
|
LogLevel value() default LogLevel.DISABLE;
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package com.alibaba.testable.core.annotation;
|
package com.alibaba.testable.core.annotation;
|
||||||
|
|
||||||
import com.alibaba.testable.core.model.ClassType;
|
import com.alibaba.testable.core.model.ClassType;
|
||||||
import com.alibaba.testable.core.model.MockDiagnose;
|
import com.alibaba.testable.core.model.LogLevel;
|
||||||
|
|
||||||
import javax.lang.model.type.NullType;
|
import javax.lang.model.type.NullType;
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
@ -30,8 +30,9 @@ public @interface MockWith {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* switch of mock diagnose information of current test class
|
* switch of mock diagnose information of current test class
|
||||||
|
* @deprecated to be removed in v0.6, use @MockDiagnose annotation instead
|
||||||
* @return enable or disable
|
* @return enable or disable
|
||||||
*/
|
*/
|
||||||
MockDiagnose diagnose() default MockDiagnose.DISABLE;
|
LogLevel diagnose() default LogLevel.DISABLE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ package com.alibaba.testable.core.model;
|
|||||||
* @author flin
|
* @author flin
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public enum MockDiagnose {
|
public enum LogLevel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Be quiet
|
* Be quiet
|
Loading…
Reference in New Issue
Block a user