mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-25 03:40:38 +08:00
add mock verifier support spock
This commit is contained in:
parent
46706ba56c
commit
58da25de53
@ -11,7 +11,7 @@
|
||||
|
||||
<font size="5">**0.6版本已发布**</font>,从`0.5.x`升级到`0.6.x`版本请参考[版本升级指南](https://alibaba.github.io/testable-mock/#/zh-cn/doc/upgrade-guide)
|
||||
|
||||
如果有遇到其他任何使用问题和建议,请直接在[Issue](https://github.com/alibaba/testable-mock/issues)中提出,也可通过[Pull Request](https://github.com/alibaba/testable-mock/pulls)提交您的代码,我们将在24小时内回复并处理
|
||||
如果有遇到其他任何使用问题和建议,请直接在[Issues](https://github.com/alibaba/testable-mock/issues)中提出,也可通过[Pull Request](https://github.com/alibaba/testable-mock/pulls)提交您的代码,我们将在24小时内回复并处理
|
||||
|
||||
-----
|
||||
|
||||
|
@ -2,17 +2,12 @@ package com.alibaba.testable.agent.handler;
|
||||
|
||||
import com.alibaba.testable.agent.handler.test.*;
|
||||
import com.alibaba.testable.agent.model.TestCaseMethodType;
|
||||
import com.alibaba.testable.agent.util.ClassUtil;
|
||||
import com.alibaba.testable.core.util.LogUtil;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.alibaba.testable.core.constant.ConstPool.THIS_REF;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
@ -24,12 +19,14 @@ public class TestClassHandler extends BaseClassWithContextHandler {
|
||||
private static final String DESC_METHOD_CLEAN = "()V";
|
||||
|
||||
private int testCaseCount = 0;
|
||||
private boolean shouldGenerateCleanupMethod = true;
|
||||
|
||||
private final Framework[] frameworkClasses = new Framework[] {
|
||||
new JUnit4Framework(),
|
||||
new JUnit5Framework(),
|
||||
new TestNgFramework(),
|
||||
new TestNgOnClassFramework()
|
||||
new TestNgOnClassFramework(),
|
||||
new SpockFramework()
|
||||
};
|
||||
|
||||
/**
|
||||
@ -43,13 +40,15 @@ public class TestClassHandler extends BaseClassWithContextHandler {
|
||||
LogUtil.warn("Failed to detect test framework for %s", cn.name);
|
||||
return;
|
||||
}
|
||||
if (!framework.hasTestAfterMethod) {
|
||||
addTestAfterMethod(cn, framework.getTestAfterAnnotation());
|
||||
}
|
||||
for (MethodNode mn : cn.methods) {
|
||||
handleTestableUtil(mn);
|
||||
handleTestCaseMethod(mn, framework);
|
||||
}
|
||||
if (shouldGenerateCleanupMethod) {
|
||||
MethodNode cleanupMethod = framework.getCleanupMethod(cn.name);
|
||||
injectMockContextClean(cleanupMethod);
|
||||
cn.methods.add(cleanupMethod);
|
||||
}
|
||||
LogUtil.diagnose(" Found %d test cases", testCaseCount);
|
||||
}
|
||||
|
||||
@ -76,23 +75,6 @@ public class TestClassHandler extends BaseClassWithContextHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addTestAfterMethod(ClassNode cn, String testAfterAnnotation) {
|
||||
MethodNode afterTestMethod = new MethodNode(ACC_PUBLIC, "testableAfterTestCase", "()V", null, null);
|
||||
afterTestMethod.visibleAnnotations = Collections.singletonList(new AnnotationNode(testAfterAnnotation));
|
||||
InsnList il = new InsnList();
|
||||
LabelNode startLabel = new LabelNode(new Label());
|
||||
LabelNode endLabel = new LabelNode(new Label());
|
||||
il.add(startLabel);
|
||||
il.add(new InsnNode(RETURN));
|
||||
il.add(endLabel);
|
||||
afterTestMethod.instructions = il;
|
||||
afterTestMethod.localVariables = Collections.singletonList(new LocalVariableNode(THIS_REF,
|
||||
ClassUtil.toByteCodeClassName(cn.name), null, startLabel, endLabel, 0));
|
||||
afterTestMethod.maxLocals = 1;
|
||||
afterTestMethod.maxStack = 0;
|
||||
cn.methods.add(afterTestMethod);
|
||||
}
|
||||
|
||||
private void handleTestCaseMethod(MethodNode mn, Framework framework) {
|
||||
TestCaseMethodType type = framework.checkMethodType(mn);
|
||||
if (type.equals(TestCaseMethodType.TEST)) {
|
||||
@ -101,6 +83,7 @@ public class TestClassHandler extends BaseClassWithContextHandler {
|
||||
testCaseCount++;
|
||||
} else if (type.equals(TestCaseMethodType.AFTER_TEST)) {
|
||||
injectMockContextClean(mn);
|
||||
shouldGenerateCleanupMethod = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,74 @@
|
||||
package com.alibaba.testable.agent.handler.test;
|
||||
|
||||
import com.alibaba.testable.agent.model.TestCaseMethodType;
|
||||
import com.alibaba.testable.agent.util.ClassUtil;
|
||||
import com.alibaba.testable.agent.util.CollectionUtil;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.alibaba.testable.core.constant.ConstPool.THIS_REF;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
import static org.objectweb.asm.Opcodes.RETURN;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
abstract public class CommonFramework implements Framework {
|
||||
|
||||
private static final String DEFAULT_CLEANUP_METHOD = "testableCleanup";
|
||||
|
||||
@Override
|
||||
public boolean fit(Set<String> classAnnotations, Set<String> methodAnnotations) {
|
||||
return CollectionUtil.containsAny(methodAnnotations, getTestMethodAnnotations());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestCaseMethodType checkMethodType(MethodNode mn) {
|
||||
if (mn.visibleAnnotations == null) {
|
||||
return TestCaseMethodType.OTHERS;
|
||||
}
|
||||
for (AnnotationNode an : mn.visibleAnnotations) {
|
||||
if (getTestMethodAnnotations().contains(an.desc)) {
|
||||
return TestCaseMethodType.TEST;
|
||||
} else if (an.desc.equals(getCleanupMethodAnnotation())) {
|
||||
return TestCaseMethodType.AFTER_TEST;
|
||||
}
|
||||
}
|
||||
return TestCaseMethodType.OTHERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodNode getCleanupMethod(String className) {
|
||||
MethodNode cleanupMethod = new MethodNode(ACC_PUBLIC, DEFAULT_CLEANUP_METHOD, "()V", null, null);
|
||||
cleanupMethod.visibleAnnotations = Collections.singletonList(new AnnotationNode(getCleanupMethodAnnotation()));
|
||||
InsnList il = new InsnList();
|
||||
LabelNode startLabel = new LabelNode(new Label());
|
||||
LabelNode endLabel = new LabelNode(new Label());
|
||||
il.add(startLabel);
|
||||
il.add(new InsnNode(RETURN));
|
||||
il.add(endLabel);
|
||||
cleanupMethod.instructions = il;
|
||||
cleanupMethod.localVariables = Collections.singletonList(new LocalVariableNode(THIS_REF,
|
||||
ClassUtil.toByteCodeClassName(className), null, startLabel, endLabel, 0));
|
||||
cleanupMethod.maxLocals = 1;
|
||||
cleanupMethod.maxStack = 0;
|
||||
return cleanupMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all annotations that identify test case method
|
||||
* @return list of annotation full name
|
||||
*/
|
||||
public abstract List<String> getTestMethodAnnotations();
|
||||
|
||||
/**
|
||||
* Get annotation that identify test cleanup method
|
||||
* @return full name of cleanup method annotation
|
||||
*/
|
||||
public abstract String getCleanupMethodAnnotation();
|
||||
|
||||
}
|
@ -1,16 +1,14 @@
|
||||
package com.alibaba.testable.agent.handler.test;
|
||||
|
||||
import com.alibaba.testable.agent.model.TestCaseMethodType;
|
||||
import com.alibaba.testable.agent.util.CollectionUtil;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
abstract public class Framework {
|
||||
|
||||
public boolean hasTestAfterMethod;
|
||||
/**
|
||||
* @author flin
|
||||
*/
|
||||
public interface Framework {
|
||||
|
||||
/**
|
||||
* Check whether the test class using current test framework
|
||||
@ -18,31 +16,20 @@ abstract public class Framework {
|
||||
* @param methodAnnotations annotations of all methods
|
||||
* @return fit or not
|
||||
*/
|
||||
public boolean fit(Set<String> classAnnotations, Set<String> methodAnnotations) {
|
||||
if (methodAnnotations.contains(getTestAfterAnnotation())) {
|
||||
hasTestAfterMethod = true;
|
||||
return true;
|
||||
} else {
|
||||
return CollectionUtil.containsAny(methodAnnotations, getTestAnnotations());
|
||||
}
|
||||
}
|
||||
boolean fit(Set<String> classAnnotations, Set<String> methodAnnotations);
|
||||
|
||||
public TestCaseMethodType checkMethodType(MethodNode mn) {
|
||||
if (mn.visibleAnnotations == null) {
|
||||
return TestCaseMethodType.OTHERS;
|
||||
}
|
||||
for (AnnotationNode an : mn.visibleAnnotations) {
|
||||
if (getTestAnnotations().contains(an.desc)) {
|
||||
return TestCaseMethodType.TEST;
|
||||
} else if (an.desc.equals(getTestAfterAnnotation())) {
|
||||
return TestCaseMethodType.AFTER_TEST;
|
||||
}
|
||||
}
|
||||
return TestCaseMethodType.OTHERS;
|
||||
}
|
||||
/**
|
||||
* Check whether a method is test or cleanup method
|
||||
* @param mn method node
|
||||
* @return test method / cleanup method / other method
|
||||
*/
|
||||
TestCaseMethodType checkMethodType(MethodNode mn);
|
||||
|
||||
public abstract List<String> getTestAnnotations();
|
||||
|
||||
public abstract String getTestAfterAnnotation();
|
||||
/**
|
||||
* Generate cleanup method with correct name and annotations
|
||||
* @param className full name of test class
|
||||
* @return cleanup method for current framework
|
||||
*/
|
||||
MethodNode getCleanupMethod(String className);
|
||||
|
||||
}
|
||||
|
@ -3,18 +3,18 @@ package com.alibaba.testable.agent.handler.test;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JUnit4Framework extends Framework {
|
||||
public class JUnit4Framework extends CommonFramework {
|
||||
|
||||
public static final String ANNOTATION_TEST = "Lorg/junit/Test;";
|
||||
private static final String ANNOTATION_AFTER_TEST = "Lorg/junit/After;";
|
||||
private static final String ANNOTATION_CLEANUP = "Lorg/junit/After;";
|
||||
|
||||
@Override
|
||||
public List<String> getTestAnnotations() {
|
||||
public List<String> getTestMethodAnnotations() {
|
||||
return Collections.singletonList(ANNOTATION_TEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTestAfterAnnotation() {
|
||||
return ANNOTATION_AFTER_TEST;
|
||||
public String getCleanupMethodAnnotation() {
|
||||
return ANNOTATION_CLEANUP;
|
||||
}
|
||||
}
|
||||
|
@ -3,19 +3,19 @@ package com.alibaba.testable.agent.handler.test;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class JUnit5Framework extends Framework {
|
||||
public class JUnit5Framework extends CommonFramework {
|
||||
|
||||
public static final String ANNOTATION_TEST = "Lorg/junit/jupiter/api/Test;";
|
||||
public static final String ANNOTATION_PARAMETERIZED_TEST = "Lorg/junit/jupiter/params/ParameterizedTest;";
|
||||
private static final String ANNOTATION_AFTER_TEST = "Lorg/junit/jupiter/api/AfterEach;";
|
||||
private static final String ANNOTATION_CLEANUP = "Lorg/junit/jupiter/api/AfterEach;";
|
||||
|
||||
@Override
|
||||
public List<String> getTestAnnotations() {
|
||||
public List<String> getTestMethodAnnotations() {
|
||||
return Arrays.asList(ANNOTATION_TEST, ANNOTATION_PARAMETERIZED_TEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTestAfterAnnotation() {
|
||||
return ANNOTATION_AFTER_TEST;
|
||||
public String getCleanupMethodAnnotation() {
|
||||
return ANNOTATION_CLEANUP;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
package com.alibaba.testable.agent.handler.test;
|
||||
|
||||
import com.alibaba.testable.agent.model.TestCaseMethodType;
|
||||
import com.alibaba.testable.agent.util.ClassUtil;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.alibaba.testable.core.constant.ConstPool.THIS_REF;
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class SpockFramework implements Framework {
|
||||
|
||||
public static final String ANNOTATION_TEST = "Lorg/spockframework/runtime/model/FeatureMetadata;";
|
||||
private static final String NAME_CLEANUP = "cleanup";
|
||||
private static final String DESC_CLEANUP = "()Ljava/lang/Object;";
|
||||
|
||||
@Override
|
||||
public boolean fit(Set<String> classAnnotations, Set<String> methodAnnotations) {
|
||||
return methodAnnotations.contains(ANNOTATION_TEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestCaseMethodType checkMethodType(MethodNode mn) {
|
||||
if (NAME_CLEANUP.equals(mn.name)) {
|
||||
return TestCaseMethodType.AFTER_TEST;
|
||||
} else if (mn.visibleAnnotations == null) {
|
||||
return TestCaseMethodType.OTHERS;
|
||||
}
|
||||
for (AnnotationNode an : mn.visibleAnnotations) {
|
||||
if (ANNOTATION_TEST.equals(an.desc)) {
|
||||
return TestCaseMethodType.TEST;
|
||||
}
|
||||
}
|
||||
return TestCaseMethodType.OTHERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodNode getCleanupMethod(String className) {
|
||||
MethodNode cleanupMethod = new MethodNode(ACC_PRIVATE, NAME_CLEANUP, DESC_CLEANUP, null, null);
|
||||
InsnList il = new InsnList();
|
||||
LabelNode startLabel = new LabelNode(new Label());
|
||||
LabelNode endLabel = new LabelNode(new Label());
|
||||
il.add(startLabel);
|
||||
il.add(new InsnNode(ACONST_NULL));
|
||||
il.add(new InsnNode(ARETURN));
|
||||
il.add(endLabel);
|
||||
cleanupMethod.instructions = il;
|
||||
cleanupMethod.localVariables = Collections.singletonList(new LocalVariableNode(THIS_REF,
|
||||
ClassUtil.toByteCodeClassName(className), null, startLabel, endLabel, 0));
|
||||
cleanupMethod.maxLocals = 1;
|
||||
cleanupMethod.maxStack = 1;
|
||||
return cleanupMethod;
|
||||
}
|
||||
}
|
@ -3,18 +3,18 @@ package com.alibaba.testable.agent.handler.test;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class TestNgFramework extends Framework {
|
||||
public class TestNgFramework extends CommonFramework {
|
||||
|
||||
private static final String ANNOTATION_TEST = "Lorg/testng/annotations/Test;";
|
||||
private static final String ANNOTATION_AFTER_TEST = "Lorg/testng/annotations/AfterMethod;";
|
||||
private static final String ANNOTATION_CLEANUP = "Lorg/testng/annotations/AfterMethod;";
|
||||
|
||||
@Override
|
||||
public List<String> getTestAnnotations() {
|
||||
public List<String> getTestMethodAnnotations() {
|
||||
return Collections.singletonList(ANNOTATION_TEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTestAfterAnnotation() {
|
||||
return ANNOTATION_AFTER_TEST;
|
||||
public String getCleanupMethodAnnotation() {
|
||||
return ANNOTATION_CLEANUP;
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,7 @@ public class TestNgOnClassFramework extends TestNgFramework {
|
||||
|
||||
@Override
|
||||
public boolean fit(Set<String> classAnnotations, Set<String> methodAnnotations) {
|
||||
if (CollectionUtil.containsAny(classAnnotations, getTestAnnotations())) {
|
||||
if (methodAnnotations.contains(getTestAfterAnnotation())) {
|
||||
hasTestAfterMethod = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return CollectionUtil.containsAny(classAnnotations, getTestMethodAnnotations());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -28,7 +22,7 @@ public class TestNgOnClassFramework extends TestNgFramework {
|
||||
return (mn.access & ACC_PUBLIC) != 0 ? TestCaseMethodType.TEST : TestCaseMethodType.OTHERS;
|
||||
}
|
||||
for (AnnotationNode an : mn.visibleAnnotations) {
|
||||
if (an.desc.equals(getTestAfterAnnotation())) {
|
||||
if (an.desc.equals(getCleanupMethodAnnotation())) {
|
||||
return TestCaseMethodType.AFTER_TEST;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user