mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-09 20:00:21 +08:00
use mock context to fetch current test case
This commit is contained in:
parent
94c5aa8621
commit
9a22f361f3
@ -32,7 +32,6 @@
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
|
@ -108,14 +108,13 @@ class DemoMockTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_able_to_get_test_case_name() throws Exception {
|
||||
void should_able_to_set_mock_context() throws Exception {
|
||||
MOCK_CONTEXT.put("case", "special_case");
|
||||
// synchronous
|
||||
assertEquals("mock_special", demoMock.callerOne());
|
||||
// asynchronous
|
||||
assertEquals("mock_special", Executors.newSingleThreadExecutor().submit(() -> demoMock.callerOne()).get());
|
||||
verify("callFromDifferentMethod").withTimes(2);
|
||||
MOCK_CONTEXT.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,10 +19,11 @@ public class PreMain {
|
||||
private static final String EQUAL = "=";
|
||||
|
||||
public static void premain(String agentArgs, Instrumentation inst) {
|
||||
// add transmittable thread local transformer
|
||||
TtlAgent.premain(agentArgs, inst);
|
||||
// add testable mock transformer
|
||||
parseArgs(agentArgs);
|
||||
inst.addTransformer(new TestableClassTransformer());
|
||||
// add TTL Transformer
|
||||
TtlAgent.premain(agentArgs, inst);
|
||||
}
|
||||
|
||||
private static void parseArgs(String args) {
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.alibaba.testable.agent.handler;
|
||||
|
||||
import com.alibaba.testable.agent.util.ClassUtil;
|
||||
import com.alibaba.testable.core.util.InvokeRecordUtil;
|
||||
import com.alibaba.testable.core.util.TestableUtil;
|
||||
import com.alibaba.testable.core.util.MockContextUtil;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
/**
|
||||
@ -13,14 +11,11 @@ abstract public class BaseClassWithContextHandler extends BaseClassHandler {
|
||||
private static final String CLASS_TESTABLE_TOOL = "com/alibaba/testable/core/tool/TestableTool";
|
||||
private static final String CLASS_TESTABLE_UTIL = "com/alibaba/testable/core/util/TestableUtil";
|
||||
private static final String CLASS_MOCK_CONTEXT_HOLDER = "com/alibaba/testable/agent/model/MockContextHolder";
|
||||
private static final String FIELD_TEST_CASE = "TEST_CASE";
|
||||
private static final String FIELD_SOURCE_METHOD = "SOURCE_METHOD";
|
||||
private static final String FIELD_MOCK_CONTEXT = "MOCK_CONTEXT";
|
||||
private static final String FIELD_PARAMETERS = "parameters";
|
||||
private static final String METHOD_CURRENT_TEST_CASE_NAME = "currentTestCaseName";
|
||||
private static final String METHOD_CURRENT_SOURCE_METHOD_NAME = "currentSourceMethodName";
|
||||
private static final String METHOD_GET_TEST_CASE_MARK = "getTestCaseMark";
|
||||
private static final String SIGNATURE_CURRENT_TEST_CASE_NAME = "(Ljava/lang/String;)Ljava/lang/String;";
|
||||
private static final String SIGNATURE_CURRENT_SOURCE_METHOD_NAME = "()Ljava/lang/String;";
|
||||
private static final String SIGNATURE_GET_TEST_CASE_MARK = "()Ljava/lang/String;";
|
||||
private static final String SIGNATURE_PARAMETERS = "Ljava/util/Map;";
|
||||
@ -42,18 +37,13 @@ abstract public class BaseClassWithContextHandler extends BaseClassHandler {
|
||||
|
||||
private boolean isTestableUtilField(FieldInsnNode fieldInsnNode) {
|
||||
return fieldInsnNode.owner.equals(CLASS_TESTABLE_TOOL) &&
|
||||
(fieldInsnNode.name.equals(FIELD_TEST_CASE) || fieldInsnNode.name.equals(FIELD_SOURCE_METHOD) ||
|
||||
fieldInsnNode.name.equals(FIELD_MOCK_CONTEXT));
|
||||
(fieldInsnNode.name.equals(FIELD_SOURCE_METHOD) || fieldInsnNode.name.equals(FIELD_MOCK_CONTEXT));
|
||||
}
|
||||
|
||||
private AbstractInsnNode[] replaceTestableUtilField(ClassNode cn, MethodNode mn, AbstractInsnNode[] instructions,
|
||||
String fieldName, int pos) {
|
||||
InsnList il = new InsnList();
|
||||
if (FIELD_TEST_CASE.equals(fieldName)) {
|
||||
il.add(new LdcInsnNode(ClassUtil.toDotSeparatedName(cn.name)));
|
||||
il.add(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, METHOD_CURRENT_TEST_CASE_NAME,
|
||||
SIGNATURE_CURRENT_TEST_CASE_NAME, false));
|
||||
} else if (FIELD_SOURCE_METHOD.equals(fieldName)) {
|
||||
if (FIELD_SOURCE_METHOD.equals(fieldName)) {
|
||||
il.add(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, METHOD_CURRENT_SOURCE_METHOD_NAME,
|
||||
SIGNATURE_CURRENT_SOURCE_METHOD_NAME, false));
|
||||
} else if (FIELD_MOCK_CONTEXT.equals(fieldName)) {
|
||||
@ -71,10 +61,8 @@ abstract public class BaseClassWithContextHandler extends BaseClassHandler {
|
||||
}
|
||||
|
||||
public static String getTestCaseMark() {
|
||||
String clazz = Thread.currentThread().getStackTrace()[InvokeRecordUtil.INDEX_OF_TEST_CLASS].getClassName();
|
||||
// TODO: temporary used
|
||||
String testClass = clazz.endsWith("Mock") ? clazz.substring(0, clazz.length() - 5) : clazz;
|
||||
String testCaseName = TestableUtil.currentTestCaseName(testClass);
|
||||
String testClass = MockContextUtil.context.get().testClassName;
|
||||
String testCaseName = MockContextUtil.context.get().testCaseName;
|
||||
return testClass + "::" + testCaseName;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package com.alibaba.testable.core.matcher;
|
||||
import com.alibaba.testable.core.error.VerifyFailedError;
|
||||
import com.alibaba.testable.core.model.Verification;
|
||||
import com.alibaba.testable.core.util.InvokeRecordUtil;
|
||||
import com.alibaba.testable.core.util.MockContextUtil;
|
||||
import com.alibaba.testable.core.util.TestableUtil;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
@ -26,8 +27,8 @@ public class InvokeVerifier {
|
||||
* @return the verifier object
|
||||
*/
|
||||
public static InvokeVerifier verify(String mockMethodName) {
|
||||
String testClass = Thread.currentThread().getStackTrace()[InvokeRecordUtil.INDEX_OF_TEST_CLASS].getClassName();
|
||||
String testCaseName = TestableUtil.currentTestCaseName(testClass);
|
||||
String testClass = MockContextUtil.context.get().testClassName;
|
||||
String testCaseName = MockContextUtil.context.get().testCaseName;
|
||||
String recordIdentify = InvokeRecordUtil.getInvokeIdentify(mockMethodName, testClass, testCaseName);
|
||||
return new InvokeVerifier(InvokeRecordUtil.getInvokeRecord(recordIdentify));
|
||||
}
|
||||
|
@ -7,13 +7,6 @@ import java.util.Map;
|
||||
*/
|
||||
public class TestableTool {
|
||||
|
||||
/**
|
||||
* Name of current test case method
|
||||
* @deprecated prefer using `MOCK_CONTEXT` to distinguish test cases
|
||||
*/
|
||||
@Deprecated
|
||||
public static String TEST_CASE;
|
||||
|
||||
/**
|
||||
* Name of the last visited method in source class
|
||||
*/
|
||||
|
@ -30,10 +30,8 @@ public class InvokeRecordUtil {
|
||||
public static void recordMockInvoke(Object[] args, boolean isConstructor, boolean isTargetClassInParameter) {
|
||||
StackTraceElement mockMethodTraceElement = Thread.currentThread().getStackTrace()[INDEX_OF_TEST_CLASS];
|
||||
String mockMethodName = mockMethodTraceElement.getMethodName();
|
||||
String mockClass = mockMethodTraceElement.getClassName();
|
||||
// TODO: temporary used
|
||||
String testClass = mockClass.substring(0, mockClass.length() - 5);
|
||||
String testCaseName = TestableUtil.currentTestCaseName(testClass);
|
||||
String testClass = MockContextUtil.context.get().testClassName;
|
||||
String testCaseName = MockContextUtil.context.get().testCaseName;
|
||||
String identify = getInvokeIdentify(mockMethodName, testClass, testCaseName);
|
||||
List<Object[]> records = getInvokeRecord(identify);
|
||||
if (isConstructor) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.alibaba.testable.core.util;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author flin
|
||||
@ -24,27 +23,6 @@ public class TestableUtil {
|
||||
return Thread.currentThread().getStackTrace()[INDEX_OF_SOURCE_METHOD].getMethodName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current test case method
|
||||
* @param testClassName name of current test class
|
||||
* @return method name
|
||||
*/
|
||||
public static String currentTestCaseName(String testClassName) {
|
||||
// try current thread
|
||||
String testCaseName = findFirstMethodFromTestClass(testClassName, Thread.currentThread().getStackTrace());
|
||||
if (testCaseName.isEmpty()) {
|
||||
Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
// travel all possible threads
|
||||
for (Thread t : threads) {
|
||||
testCaseName = findFirstMethodFromTestClass(testClassName, t.getStackTrace());
|
||||
if (!testCaseName.isEmpty()) {
|
||||
return testCaseName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return testCaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file name and line number of where current method was called
|
||||
* @return in "filename:linenumber" format
|
||||
@ -54,31 +32,4 @@ public class TestableUtil {
|
||||
return stack.getFileName() + ":" + stack.getLineNumber();
|
||||
}
|
||||
|
||||
private static String findFirstMethodFromTestClass(String testClassName, StackTraceElement[] stack) {
|
||||
for (int i = stack.length - 1; i >= 0; i--) {
|
||||
if (getOuterClassName(stack[i].getClassName()).equals(testClassName)) {
|
||||
return stack[i].getClassName().indexOf('$') > 0 ?
|
||||
// test case using async call
|
||||
getMethodNameFromLambda(stack[i].getClassName()) :
|
||||
// in case of lambda method
|
||||
getMethodNameFromLambda(stack[i].getMethodName());
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String getMethodNameFromLambda(String originName) {
|
||||
int beginOfMethodName = originName.indexOf('$');
|
||||
if (beginOfMethodName < 0) {
|
||||
return originName;
|
||||
}
|
||||
int endOfMethodName = originName.indexOf('$', beginOfMethodName + 1);
|
||||
return originName.substring(beginOfMethodName + 1, endOfMethodName);
|
||||
}
|
||||
|
||||
private static String getOuterClassName(String className) {
|
||||
int posOfInnerClass = className.indexOf('$');
|
||||
return posOfInnerClass > 0 ? className.substring(0, posOfInnerClass) : className;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
package com.alibaba.testable.core.util;
|
||||
|
||||
import com.alibaba.testable.core.accessor.PrivateAccessor;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TestableUtilTest {
|
||||
|
||||
@Test
|
||||
void should_get_outer_class_name() {
|
||||
assertEquals("com.alibaba.testable.demo.DemoMockTest",
|
||||
PrivateAccessor.<String>invokeStatic(TestableUtil.class, "getOuterClassName", "com.alibaba.testable.demo.DemoMockTest$should_able_to_get_source_method_name$1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_get_method_name_from_lambda_class_or_method() {
|
||||
assertEquals("should_able_to_get_source_method_name",
|
||||
PrivateAccessor.<String>invokeStatic(TestableUtil.class, "getMethodNameFromLambda", "com.alibaba.testable.demo.DemoMockTest$should_able_to_get_source_method_name$1"));
|
||||
assertEquals("should_able_to_get_source_method_name",
|
||||
PrivateAccessor.<String>invokeStatic(TestableUtil.class, "getMethodNameFromLambda", "lambda$should_able_to_get_source_method_name$0"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user