From c8115f96235e548cb629526c3e2f772d84aa3012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Thu, 10 Dec 2020 15:47:55 +0800 Subject: [PATCH] add verbose log when test start --- .../agent/handler/TestClassHandler.java | 38 ++++++++++++------- .../testable/core/util/InvokeRecordUtil.java | 4 +- .../testable/core/util/TestableUtil.java | 15 +++++++- 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java index ebcffe0..3cc9778 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java @@ -8,9 +8,7 @@ import com.alibaba.testable.core.tool.TestableConst; import org.objectweb.asm.tree.*; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * @author flin @@ -24,13 +22,12 @@ public class TestClassHandler extends BaseClassHandler { private static final String FIELD_SOURCE_METHOD = "SOURCE_METHOD"; 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_MARK_TEST_CASE_BEGIN = "markTestCaseBegin"; private static final String METHOD_RECORD_MOCK_INVOKE = "recordMockInvoke"; - private static final String SIGNATURE_TESTABLE_UTIL_METHOD = "(Ljava/lang/Object;)Ljava/lang/String;"; + private static final String SIGNATURE_CURRENT_TEST_CASE_NAME = "(Ljava/lang/Object;)Ljava/lang/String;"; + private static final String SIGNATURE_CURRENT_SOURCE_METHOD_NAME = "()Ljava/lang/String;"; + private static final String SIGNATURE_VOID_METHOD_WITHOUT_PARAMETER = "()V"; private static final String SIGNATURE_INVOKE_RECORDER_METHOD = "([Ljava/lang/Object;Z)V"; - private static final Map FIELD_TO_METHOD_MAPPING = new HashMap() {{ - put(FIELD_TEST_CASE, METHOD_CURRENT_TEST_CASE_NAME); - put(FIELD_SOURCE_METHOD, METHOD_CURRENT_SOURCE_METHOD_NAME); - }}; /** * Handle bytecode of test class @@ -91,11 +88,18 @@ public class TestClassHandler extends BaseClassHandler { private AbstractInsnNode[] replaceTestableUtilField(MethodNode mn, AbstractInsnNode[] instructions, String fieldName, int pos) { InsnList il = new InsnList(); - il.add(new VarInsnNode(ALOAD, 0)); - il.add(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, FIELD_TO_METHOD_MAPPING.get(fieldName), - SIGNATURE_TESTABLE_UTIL_METHOD, false)); - mn.instructions.insert(instructions[pos], il); - mn.instructions.remove(instructions[pos]); + if (FIELD_TEST_CASE.equals(fieldName)) { + il.add(new VarInsnNode(ALOAD, 0)); + 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)) { + il.add(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, METHOD_CURRENT_SOURCE_METHOD_NAME, + SIGNATURE_CURRENT_SOURCE_METHOD_NAME, false)); + } + if (il.size() > 0) { + mn.instructions.insert(instructions[pos], il); + mn.instructions.remove(instructions[pos]); + } return mn.instructions.toArray(); } @@ -181,18 +185,24 @@ public class TestClassHandler extends BaseClassHandler { private void injectTestableRef(ClassNode cn, MethodNode mn) { InsnList il = new InsnList(); + // Initialize "_testableInternalRef" il.add(new VarInsnNode(ALOAD, 0)); il.add(new FieldInsnNode(PUTSTATIC, cn.name, ConstPool.TESTABLE_INJECT_REF, ClassUtil.toByteCodeClassName(cn.name))); - mn.instructions.insertBefore(mn.instructions.get(0), il); + // Invoke "markTestCaseBegin" + il.add(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, METHOD_MARK_TEST_CASE_BEGIN, + SIGNATURE_VOID_METHOD_WITHOUT_PARAMETER, false)); + mn.instructions.insertBefore(mn.instructions.getFirst(), il); } /** * Different unit test framework may have different @Test annotation * but they should always NOT private, protected or static + * and has neither parameter nor return value */ private boolean couldBeTestMethod(MethodNode mn) { - return (mn.access & (ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC)) == 0 ; + return (mn.access & (ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC)) == 0 && + mn.desc.equals(SIGNATURE_VOID_METHOD_WITHOUT_PARAMETER); } } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/util/InvokeRecordUtil.java b/testable-core/src/main/java/com/alibaba/testable/core/util/InvokeRecordUtil.java index b22aa48..94ee7be 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/util/InvokeRecordUtil.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/util/InvokeRecordUtil.java @@ -35,10 +35,10 @@ public class InvokeRecordUtil { List records = getInvokeRecord(identify); if (isConstructor) { records.add(args); - LogUtil.verbose("Mock constructor invoked \"%s\"", identify); + LogUtil.verbose(" Mock constructor invoked \"%s\"", identify); } else { records.add(slice(args, 1)); - LogUtil.verbose("Mock method invoked \"%s\"", identify); + LogUtil.verbose(" Mock method invoked \"%s\"", identify); } INVOKE_RECORDS.put(identify, records); } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/util/TestableUtil.java b/testable-core/src/main/java/com/alibaba/testable/core/util/TestableUtil.java index bd4da15..cf60528 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/util/TestableUtil.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/util/TestableUtil.java @@ -15,6 +15,10 @@ public class TestableUtil { * [0]Thread.getStackTrace() → [1]previousStackLocation() → [2]Invoker -> [3]Caller of invoker */ private static final int INDEX_OF_CALLER_METHOD = 3; + /** + * [0]Thread.getStackTrace() → [1]markTestCaseBegin() → [2]TestCaseMethod + */ + private static final int INDEX_OF_TEST_CASE_METHOD = 2; /** * Just a special number to identify test worker thread */ @@ -22,10 +26,9 @@ public class TestableUtil { /** * Get the last visit method in source file - * @param testClassRef usually `this` variable of the test class * @return method name */ - public static String currentSourceMethodName(Object testClassRef) { + public static String currentSourceMethodName() { return Thread.currentThread().getStackTrace()[INDEX_OF_SOURCE_METHOD].getMethodName(); } @@ -79,6 +82,14 @@ public class TestableUtil { return stack.getFileName() + ":" + stack.getLineNumber(); } + /** + * Do prepare when probable test case start + */ + public static void markTestCaseBegin() { + String testCaseName = Thread.currentThread().getStackTrace()[INDEX_OF_TEST_CASE_METHOD].getMethodName(); + LogUtil.verbose("Start testcase: " + testCaseName); + } + private static Thread findTestWorkerThread(Set threads) { for (Thread t : threads) { if (t.getPriority() == TEST_WORKER_THREAD_PRIORITY) {