add verbose log when test start

This commit is contained in:
金戟 2020-12-10 15:47:55 +08:00
parent 4def468d85
commit c8115f9623
3 changed files with 39 additions and 18 deletions

View File

@ -8,9 +8,7 @@ import com.alibaba.testable.core.tool.TestableConst;
import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author flin * @author flin
@ -24,13 +22,12 @@ public class TestClassHandler extends BaseClassHandler {
private static final String FIELD_SOURCE_METHOD = "SOURCE_METHOD"; 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_TEST_CASE_NAME = "currentTestCaseName";
private static final String METHOD_CURRENT_SOURCE_METHOD_NAME = "currentSourceMethodName"; 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 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 String SIGNATURE_INVOKE_RECORDER_METHOD = "([Ljava/lang/Object;Z)V";
private static final Map<String, String> FIELD_TO_METHOD_MAPPING = new HashMap<String, String>() {{
put(FIELD_TEST_CASE, METHOD_CURRENT_TEST_CASE_NAME);
put(FIELD_SOURCE_METHOD, METHOD_CURRENT_SOURCE_METHOD_NAME);
}};
/** /**
* Handle bytecode of test class * Handle bytecode of test class
@ -91,11 +88,18 @@ public class TestClassHandler extends BaseClassHandler {
private AbstractInsnNode[] replaceTestableUtilField(MethodNode mn, AbstractInsnNode[] instructions, private AbstractInsnNode[] replaceTestableUtilField(MethodNode mn, AbstractInsnNode[] instructions,
String fieldName, int pos) { String fieldName, int pos) {
InsnList il = new InsnList(); InsnList il = new InsnList();
il.add(new VarInsnNode(ALOAD, 0)); if (FIELD_TEST_CASE.equals(fieldName)) {
il.add(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, FIELD_TO_METHOD_MAPPING.get(fieldName), il.add(new VarInsnNode(ALOAD, 0));
SIGNATURE_TESTABLE_UTIL_METHOD, false)); il.add(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, METHOD_CURRENT_TEST_CASE_NAME,
mn.instructions.insert(instructions[pos], il); SIGNATURE_CURRENT_TEST_CASE_NAME, false));
mn.instructions.remove(instructions[pos]); } 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(); return mn.instructions.toArray();
} }
@ -181,18 +185,24 @@ public class TestClassHandler extends BaseClassHandler {
private void injectTestableRef(ClassNode cn, MethodNode mn) { private void injectTestableRef(ClassNode cn, MethodNode mn) {
InsnList il = new InsnList(); InsnList il = new InsnList();
// Initialize "_testableInternalRef"
il.add(new VarInsnNode(ALOAD, 0)); il.add(new VarInsnNode(ALOAD, 0));
il.add(new FieldInsnNode(PUTSTATIC, cn.name, ConstPool.TESTABLE_INJECT_REF, il.add(new FieldInsnNode(PUTSTATIC, cn.name, ConstPool.TESTABLE_INJECT_REF,
ClassUtil.toByteCodeClassName(cn.name))); 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 * Different unit test framework may have different @Test annotation
* but they should always NOT private, protected or static * but they should always NOT private, protected or static
* and has neither parameter nor return value
*/ */
private boolean couldBeTestMethod(MethodNode mn) { 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);
} }
} }

View File

@ -35,10 +35,10 @@ public class InvokeRecordUtil {
List<Object[]> records = getInvokeRecord(identify); List<Object[]> records = getInvokeRecord(identify);
if (isConstructor) { if (isConstructor) {
records.add(args); records.add(args);
LogUtil.verbose("Mock constructor invoked \"%s\"", identify); LogUtil.verbose(" Mock constructor invoked \"%s\"", identify);
} else { } else {
records.add(slice(args, 1)); records.add(slice(args, 1));
LogUtil.verbose("Mock method invoked \"%s\"", identify); LogUtil.verbose(" Mock method invoked \"%s\"", identify);
} }
INVOKE_RECORDS.put(identify, records); INVOKE_RECORDS.put(identify, records);
} }

View File

@ -15,6 +15,10 @@ public class TestableUtil {
* [0]Thread.getStackTrace() [1]previousStackLocation() [2]Invoker -> [3]Caller of invoker * [0]Thread.getStackTrace() [1]previousStackLocation() [2]Invoker -> [3]Caller of invoker
*/ */
private static final int INDEX_OF_CALLER_METHOD = 3; 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 * Just a special number to identify test worker thread
*/ */
@ -22,10 +26,9 @@ public class TestableUtil {
/** /**
* Get the last visit method in source file * Get the last visit method in source file
* @param testClassRef usually `this` variable of the test class
* @return method name * @return method name
*/ */
public static String currentSourceMethodName(Object testClassRef) { public static String currentSourceMethodName() {
return Thread.currentThread().getStackTrace()[INDEX_OF_SOURCE_METHOD].getMethodName(); return Thread.currentThread().getStackTrace()[INDEX_OF_SOURCE_METHOD].getMethodName();
} }
@ -79,6 +82,14 @@ public class TestableUtil {
return stack.getFileName() + ":" + stack.getLineNumber(); 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<Thread> threads) { private static Thread findTestWorkerThread(Set<Thread> threads) {
for (Thread t : threads) { for (Thread t : threads) {
if (t.getPriority() == TEST_WORKER_THREAD_PRIORITY) { if (t.getPriority() == TEST_WORKER_THREAD_PRIORITY) {