mirror of
https://github.com/alibaba/testable-mock.git
synced 2026-08-23 11:43:29 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5904ad99cb | ||
|
|
74fbc5b53f | ||
|
|
f6b5bab250 | ||
|
|
f2feb3cc68 |
@@ -13,8 +13,8 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.1')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.2')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<junit.version>5.6.2</junit.version>
|
||||
<testable.version>0.6.1</testable.version>
|
||||
<testable.version>0.6.2</testable.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
1
demo/java-demo/src/test/resources/testable.properties
Normal file
1
demo/java-demo/src/test/resources/testable.properties
Normal file
@@ -0,0 +1 @@
|
||||
omni.constructor.enhance.enable = true
|
||||
@@ -16,8 +16,8 @@ dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.6.2")
|
||||
testImplementation("com.alibaba.testable:testable-all:0.6.1")
|
||||
testAnnotationProcessor("com.alibaba.testable:testable-processor:0.6.1")
|
||||
testImplementation("com.alibaba.testable:testable-all:0.6.2")
|
||||
testAnnotationProcessor("com.alibaba.testable:testable-processor:0.6.2")
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<junit.version>5.6.2</junit.version>
|
||||
<testable.version>0.6.1</testable.version>
|
||||
<testable.version>0.6.2</testable.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
1
demo/kotlin-demo/src/test/resources/testable.properties
Normal file
1
demo/kotlin-demo/src/test/resources/testable.properties
Normal file
@@ -0,0 +1 @@
|
||||
omni.constructor.enhance.enable = true
|
||||
@@ -14,8 +14,8 @@ repositories {
|
||||
dependencies {
|
||||
testImplementation 'org.codehaus.groovy:groovy-all:3.0.7'
|
||||
testImplementation 'org.spockframework:spock-core:2.0-M5-groovy-3.0'
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.1')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.2')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<testable.version>0.6.1</testable.version>
|
||||
<testable.version>0.6.2</testable.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
# Release Note
|
||||
|
||||
## 0.6.2
|
||||
- support setup global testable agent configure via properties file
|
||||
- disable OmniConstructor bytecode enhancement by default
|
||||
- fix a `Spring` framework compatibility issue with OmniConstructor
|
||||
|
||||
## 0.6.1
|
||||
- generate mock scanning log file automatically, for self-troubleshooting
|
||||
- fix a `Spock` test frame compatibility issue
|
||||
- fix a `Spock` test framework compatibility issue
|
||||
- fix a `Gradle` unit test runtime compatibility issue
|
||||
|
||||
## 0.6.0
|
||||
|
||||
@@ -16,7 +16,7 @@ It is recommended to add a `property` field that identifies the TestableMock ver
|
||||
|
||||
```xml
|
||||
<properties>
|
||||
<testable.version>0.6.1</testable.version>
|
||||
<testable.version>0.6.2</testable.version>
|
||||
</properties>
|
||||
```
|
||||
|
||||
@@ -63,8 +63,8 @@ Add dependence of `TestableMock` in `build.gradle` file:
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.1')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.2')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# Release Note
|
||||
|
||||
## 0.6.2
|
||||
- 支持通过Properties文件配置TestableAgent
|
||||
- 默认禁用OmniConstructor相关的字节码增强
|
||||
- 修复OmniConstructor与`Spring`框架的兼容问题(issue-129)
|
||||
|
||||
## 0.6.1
|
||||
- 自动生成Mock扫描过程日志文件,便于自助排查问题
|
||||
- 修复一处`Spock`测试框架的兼容问题 (issue-121)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
```xml
|
||||
<properties>
|
||||
<testable.version>0.6.1</testable.version>
|
||||
<testable.version>0.6.2</testable.version>
|
||||
</properties>
|
||||
```
|
||||
|
||||
@@ -63,8 +63,8 @@
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.1')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.1')
|
||||
testImplementation('com.alibaba.testable:testable-all:0.6.2')
|
||||
testAnnotationProcessor('com.alibaba.testable:testable-processor:0.6.2')
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.testable</groupId>
|
||||
<artifactId>testable-parent</artifactId>
|
||||
<version>0.6.1</version>
|
||||
<version>0.6.2</version>
|
||||
<relativePath>../testable-parent</relativePath>
|
||||
</parent>
|
||||
<artifactId>testable-agent</artifactId>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.alibaba.testable.agent;
|
||||
|
||||
import com.alibaba.testable.agent.config.PropertiesParser;
|
||||
import com.alibaba.testable.agent.transformer.TestableClassTransformer;
|
||||
import com.alibaba.testable.agent.util.GlobalConfig;
|
||||
import com.alibaba.testable.core.model.MockScope;
|
||||
@@ -21,13 +22,15 @@ public class PreMain {
|
||||
private static final String DUMP_PATH = "dumpPath";
|
||||
private static final String PKG_PREFIX = "pkgPrefix";
|
||||
private static final String MOCK_SCOPE = "mockScope";
|
||||
private static final String CONFIG_FILE = "configFile";
|
||||
private static final String EQUAL = "=";
|
||||
private static boolean enhanceThreadLocal = false;
|
||||
private static String configFilePath = null;
|
||||
|
||||
public static void premain(String agentArgs, Instrumentation inst) {
|
||||
parseArgs(agentArgs);
|
||||
new PropertiesParser().parseFile(configFilePath);
|
||||
GlobalConfig.setupLogRootPath();
|
||||
if (enhanceThreadLocal) {
|
||||
if (GlobalConfig.isEnhanceThreadLocal()) {
|
||||
// add transmittable thread local transformer
|
||||
TtlAgent.premain(agentArgs, inst);
|
||||
}
|
||||
@@ -56,11 +59,13 @@ public class PreMain {
|
||||
GlobalConfig.setPkgPrefix(v);
|
||||
} else if (k.equals(MOCK_SCOPE)) {
|
||||
GlobalConfig.setDefaultMockScope(MockScope.of(v));
|
||||
} else if (k.equals(CONFIG_FILE)) {
|
||||
configFilePath = v;
|
||||
}
|
||||
} else {
|
||||
// parameter with single value
|
||||
if (a.equals(USE_THREAD_POOL)) {
|
||||
enhanceThreadLocal = true;
|
||||
GlobalConfig.setEnhanceThreadLocal(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.alibaba.testable.agent.config;
|
||||
|
||||
import com.alibaba.testable.agent.util.GlobalConfig;
|
||||
import com.alibaba.testable.agent.util.PathUtil;
|
||||
import com.alibaba.testable.core.model.MockScope;
|
||||
import com.alibaba.testable.core.util.LogUtil;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
|
||||
import static com.alibaba.testable.agent.constant.ConstPool.PROPERTY_USER_DIR;
|
||||
|
||||
public class PropertiesParser {
|
||||
|
||||
private static final String DEFAULT_CONFIG_FILE = "src/test/resources/testable.properties";
|
||||
private static final String LOG_LEVEL = "log.level";
|
||||
private static final String LOG_FILE = "log.file";
|
||||
private static final String DUMP_PATH = "dump.path";
|
||||
private static final String PKG_PREFIX_WHITELIST = "custom.pkgPrefix.whiteList";
|
||||
private static final String DEFAULT_MOCK_SCOPE = "mock.scope.default";
|
||||
private static final String ENABLE_THREAD_POOL = "thread.pool.enhance.enable";
|
||||
private static final String ENABLE_OMNI_INJECT = "omni.constructor.enhance.enable";
|
||||
|
||||
public void parseFile(String configFilePath) {
|
||||
String path = (configFilePath == null) ? DEFAULT_CONFIG_FILE : configFilePath;
|
||||
String fullPath = PathUtil.join(System.getProperty(PROPERTY_USER_DIR), path);
|
||||
Properties pps = new Properties();
|
||||
try {
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(fullPath));
|
||||
pps.load(in);
|
||||
LogUtil.verbose("Loaded configure file %s", fullPath);
|
||||
} catch (IOException e) {
|
||||
if (configFilePath == null) {
|
||||
LogUtil.verbose("No configure file found, skip.");
|
||||
} else {
|
||||
LogUtil.warn("No configure file found at %s", fullPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
parsePropertiesContent(pps);
|
||||
}
|
||||
|
||||
private void parsePropertiesContent(Properties pps) {
|
||||
Enumeration<?> en = pps.propertyNames();
|
||||
while(en.hasMoreElements()) {
|
||||
String k = (String)en.nextElement();
|
||||
String v = pps.getProperty(k);
|
||||
if (k.equals(LOG_LEVEL)) {
|
||||
GlobalConfig.setLogLevel(v);
|
||||
} else if (k.equals(LOG_FILE)) {
|
||||
GlobalConfig.setLogFile(v);
|
||||
} else if (k.equals(DUMP_PATH)) {
|
||||
GlobalConfig.setDumpPath(v);
|
||||
} else if (k.equals(PKG_PREFIX_WHITELIST)) {
|
||||
GlobalConfig.setPkgPrefix(v);
|
||||
} else if (k.equals(DEFAULT_MOCK_SCOPE)) {
|
||||
GlobalConfig.setDefaultMockScope(MockScope.of(v));
|
||||
} else if (k.equals(ENABLE_THREAD_POOL)) {
|
||||
GlobalConfig.setEnhanceThreadLocal(Boolean.parseBoolean(v));
|
||||
} else if (k.equals(ENABLE_OMNI_INJECT)) {
|
||||
GlobalConfig.setEnhanceOmniConstructor(Boolean.parseBoolean(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,8 @@ public class OmniClassHandler extends BaseClassHandler {
|
||||
private static final String METHOD_START = "(";
|
||||
private static final String VOID_METHOD_END = ")V";
|
||||
private static final String VOID_METHOD = "()V";
|
||||
private static final String ENABLE_CONFIGURATION_PROPERTIES
|
||||
= "Lorg/springframework/boot/context/properties/EnableConfigurationProperties;";
|
||||
|
||||
private static final String[] JUNIT_TEST_ANNOTATIONS = new String[] {
|
||||
JUnit4Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_PARAMETERIZED_TEST
|
||||
@@ -31,9 +33,13 @@ public class OmniClassHandler extends BaseClassHandler {
|
||||
|
||||
@Override
|
||||
protected void transform(ClassNode cn) {
|
||||
if (isInterface(cn) || isJunitTestClass(cn) || isUninstantiableClass(cn)) {
|
||||
if (isInterface(cn) || isJunitTestClass(cn) || isUninstantiableClass(cn) || hasSpecialAnnotation(cn)) {
|
||||
return;
|
||||
}
|
||||
addConstructorWithNullTypeParameter(cn);
|
||||
}
|
||||
|
||||
private void addConstructorWithNullTypeParameter(ClassNode cn) {
|
||||
MethodNode constructor = new MethodNode(ACC_PUBLIC, CONSTRUCTOR,
|
||||
METHOD_START + ClassUtil.toByteCodeClassName(NULL_TYPE) + VOID_METHOD_END, null, null);
|
||||
LabelNode start = new LabelNode(new Label());
|
||||
@@ -51,6 +57,18 @@ public class OmniClassHandler extends BaseClassHandler {
|
||||
cn.methods.add(constructor);
|
||||
}
|
||||
|
||||
private boolean hasSpecialAnnotation(ClassNode cn) {
|
||||
if (cn.visibleAnnotations == null) {
|
||||
return false;
|
||||
}
|
||||
for (AnnotationNode an : cn.visibleAnnotations) {
|
||||
if (an.desc.equals(ENABLE_CONFIGURATION_PROPERTIES)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isUninstantiableClass(ClassNode cn) {
|
||||
// if the class has no even default constructor, skip it
|
||||
for (MethodNode mn : cn.methods) {
|
||||
|
||||
@@ -40,8 +40,7 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
||||
/**
|
||||
* Just avoid spend time to scan those surely non-user classes, should keep these lists as tiny as possible
|
||||
*/
|
||||
private final String[] BLACKLIST_PREFIXES = new String[] { "sun/", "com/sun/", "org/gradle/",
|
||||
"org/springframework/boot/autoconfigure/" };
|
||||
private final String[] BLACKLIST_PREFIXES = new String[] { "sun/", "com/sun/", "org/gradle/" };
|
||||
|
||||
public MockClassParser mockClassParser = new MockClassParser();
|
||||
|
||||
@@ -53,7 +52,8 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
||||
return null;
|
||||
}
|
||||
LogUtil.verbose("Handle class: " + className);
|
||||
byte[] bytes = new OmniClassHandler().getBytes(classFileBuffer);
|
||||
byte[] bytes = GlobalConfig.isEnhanceOmniConstructor() ?
|
||||
new OmniClassHandler().getBytes(classFileBuffer) : classFileBuffer;
|
||||
ClassNode cn = ClassUtil.getClassNode(className);
|
||||
if (cn != null) {
|
||||
return transformMock(bytes, cn);
|
||||
|
||||
@@ -25,6 +25,8 @@ public class GlobalConfig {
|
||||
private static String dumpPath = null;
|
||||
private static String pkgPrefix = null;
|
||||
private static MockScope defaultMockScope = MockScope.GLOBAL;
|
||||
private static boolean enhanceThreadLocal = false;
|
||||
private static boolean enhanceOmniConstructor = false;
|
||||
|
||||
public static void setLogLevel(String level) {
|
||||
if (level.equals(MUTE)) {
|
||||
@@ -78,4 +80,20 @@ public class GlobalConfig {
|
||||
LogUtil.setGlobalLogPath(PathUtil.join(System.getProperty(PROPERTY_USER_DIR), logFile));
|
||||
}
|
||||
}
|
||||
|
||||
public static void setEnhanceThreadLocal(boolean enabled) {
|
||||
enhanceThreadLocal = enabled;
|
||||
}
|
||||
|
||||
public static boolean isEnhanceThreadLocal() {
|
||||
return enhanceThreadLocal;
|
||||
}
|
||||
|
||||
public static void setEnhanceOmniConstructor(boolean enabled) {
|
||||
enhanceOmniConstructor = enabled;
|
||||
}
|
||||
|
||||
public static boolean isEnhanceOmniConstructor() {
|
||||
return enhanceOmniConstructor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.testable</groupId>
|
||||
<artifactId>testable-parent</artifactId>
|
||||
<version>0.6.1</version>
|
||||
<version>0.6.2</version>
|
||||
<relativePath>../testable-parent</relativePath>
|
||||
</parent>
|
||||
<artifactId>testable-all</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.testable</groupId>
|
||||
<artifactId>testable-parent</artifactId>
|
||||
<version>0.6.1</version>
|
||||
<version>0.6.2</version>
|
||||
<relativePath>../testable-parent</relativePath>
|
||||
</parent>
|
||||
<artifactId>testable-core</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.testable</groupId>
|
||||
<artifactId>testable-parent</artifactId>
|
||||
<version>0.6.1</version>
|
||||
<version>0.6.2</version>
|
||||
<relativePath>../testable-parent</relativePath>
|
||||
</parent>
|
||||
<artifactId>testable-maven-plugin</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.alibaba.testable</groupId>
|
||||
<artifactId>testable-parent</artifactId>
|
||||
<version>0.6.1</version>
|
||||
<version>0.6.2</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>testable-parent</name>
|
||||
<description>Unit test enhancement toolkit</description>
|
||||
@@ -42,7 +42,7 @@
|
||||
<plugin.gpg.version>1.6</plugin.gpg.version>
|
||||
<plugin.staging.version>1.6.8</plugin.staging.version>
|
||||
<plugin.maven.version>3.6.0</plugin.maven.version>
|
||||
<testable.version>0.6.1</testable.version>
|
||||
<testable.version>0.6.2</testable.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.alibaba.testable</groupId>
|
||||
<artifactId>testable-parent</artifactId>
|
||||
<version>0.6.1</version>
|
||||
<version>0.6.2</version>
|
||||
<relativePath>../testable-parent</relativePath>
|
||||
</parent>
|
||||
<artifactId>testable-processor</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user