fix bytecode order and async test case

This commit is contained in:
金戟 2020-10-21 21:45:12 +08:00
parent 2fda70d7b4
commit 26712108d6
7 changed files with 81 additions and 22 deletions

View File

@ -83,10 +83,11 @@ public class TestClassHandler extends BaseClassHandler {
private AbstractInsnNode[] replaceTestableUtilField(MethodNode mn, AbstractInsnNode[] instructions,
String fieldName, int pos) {
InsnList insnNodes = new InsnList();
insnNodes.insert(new VarInsnNode(ALOAD, 0));
// NOTE: will insert in reversed order
insnNodes.insert(new MethodInsnNode(INVOKESTATIC, CLASS_TESTABLE_UTIL, FIELD_TO_METHOD_MAPPING.get(fieldName),
SIGNATURE_TESTABLE_UTIL_METHOD, false));
mn.instructions.insertBefore(instructions[pos], insnNodes);
insnNodes.insert(new VarInsnNode(ALOAD, 0));
mn.instructions.insert(instructions[pos], insnNodes);
mn.instructions.remove(instructions[pos]);
return mn.instructions.toArray();
}

View File

@ -5,7 +5,14 @@ package com.alibaba.testable.core.tool;
*/
public class TestableTool {
/**
* Name of current test case method
*/
public static String TEST_CASE;
/**
* Name of the last visited method in source class
*/
public static String SOURCE_METHOD;
}

View File

@ -7,6 +7,10 @@ import java.io.*;
*/
public class ResourceUtil {
/**
* Read content of a text file from resource folder
* @param filePath file to read
*/
public static String fetchText(String filePath) {
InputStream in = ResourceUtil.class.getResourceAsStream("/" + filePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
@ -24,6 +28,10 @@ public class ResourceUtil {
}
}
/**
* Read content of a binary file from resource folder
* @param filePath file to read
*/
public static byte[] fetchBinary(String filePath) {
InputStream in = ResourceUtil.class.getResourceAsStream("/" + filePath);
if (in == null) {

View File

@ -7,6 +7,11 @@ import java.util.List;
*/
public class StringUtil {
/**
* Join strings
* @param list strings to join
* @param conjunction connection character
*/
static public String join(List<String> list, String conjunction)
{
StringBuilder sb = new StringBuilder();

View File

@ -7,19 +7,27 @@ import com.alibaba.testable.core.constant.ConstPool;
*/
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) {
Class<?> testClass = testClassRef.getClass();
StackTraceElement[] stack = getMainThread().getStackTrace();
String testClassName = getRealClassName(testClass);
String sourceClassName = testClassName.substring(0, testClassName.length() - ConstPool.TEST_POSTFIX.length());
for (int i = stack.length - 1; i >= 0; i--) {
if (stack[i].getClassName().equals(sourceClassName)) {
return stack[i].getMethodName();
}
String sourceMethod = findLastMethodFromSourceClass(sourceClassName, getMainThread().getStackTrace());
if (sourceMethod.isEmpty()) {
return findLastMethodFromSourceClass(sourceClassName, Thread.currentThread().getStackTrace());
}
return "";
return sourceMethod;
}
/**
* Get current test case method
* @param testClassRef usually `this` variable of the test class
* @return method name
*/
public static String currentTestCaseName(Object testClassRef) {
Class<?> testClass = testClassRef.getClass();
StackTraceElement[] stack = getMainThread().getStackTrace();
@ -32,6 +40,15 @@ public class TestableUtil {
return "";
}
private static String findLastMethodFromSourceClass(String sourceClassName, StackTraceElement[] stack) {
for (StackTraceElement element : stack) {
if (element.getClassName().equals(sourceClassName)) {
return element.getMethodName();
}
}
return "";
}
private static String getRealClassName(Class<?> testClass) {
String className = testClass.getName();
int posOfInnerClass = className.lastIndexOf('$');
@ -44,6 +61,7 @@ public class TestableUtil {
return t;
}
}
// usually impossible to go here
return Thread.currentThread();
}

View File

@ -6,6 +6,7 @@ import com.alibaba.testable.core.annotation.TestableInject;
import org.junit.jupiter.api.Test;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import static com.alibaba.testable.core.tool.TestableTool.SOURCE_METHOD;
import static com.alibaba.testable.core.tool.TestableTool.TEST_CASE;
@ -41,6 +42,9 @@ class DemoServiceTest {
@TestableInject
private String callFromDifferentMethod() {
if (TEST_CASE.equals("should_able_to_get_test_case_name")) {
return "mock_special";
}
switch (SOURCE_METHOD) {
case "callerOne": return "mock_one";
default: return "mock_others";
@ -81,15 +85,19 @@ class DemoServiceTest {
@Test
void should_able_to_get_source_method_name() throws Exception {
assertEquals("mock_one_mock_others", demoService.callerTwo() + "_" + demoService.callerOne());
assertEquals("mock_one_mock_others", ((Callable<String>)() ->
demoService.callerOne() + "_" + demoService.callerTwo()).call());
// synchronous
assertEquals("mock_one_mock_others", demoService.callerOne() + "_" + demoService.callerTwo());
// asynchronous
assertEquals("mock_one_mock_others",
Executors.newSingleThreadExecutor().submit(() -> demoService.callerOne() + "_" + demoService.callerTwo()).get());
}
@Test
void should_able_to_get_test_case_name() throws Exception {
assertEquals("should_able_to_get_test_case_name", TEST_CASE);
assertEquals("should_able_to_get_test_case_name", ((Callable<String>)() -> TEST_CASE).call());
// synchronous
assertEquals("mock_special", demoService.callerOne());
// asynchronous
assertEquals("mock_special", Executors.newSingleThreadExecutor().submit(() -> demoService.callerOne()).get());
}
}

View File

@ -7,7 +7,7 @@ import com.alibaba.testable.core.tool.TestableTool.SOURCE_METHOD
import com.alibaba.testable.core.tool.TestableTool.TEST_CASE
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.util.concurrent.Callable
import java.util.concurrent.Executors
@EnableTestable
@ -29,9 +29,15 @@ internal class DemoServiceTest {
private fun startsWith(self: BlackBox, s: String) = false
@TestableInject
private fun callFromDifferentMethod() = when (SOURCE_METHOD) {
"callerOne" -> "mock_one"
else -> "mock_others"
private fun callFromDifferentMethod(): String {
return if (TEST_CASE == "should_able_to_get_test_case_name") {
"mock_special"
} else {
when (SOURCE_METHOD) {
"callerOne" -> "mock_one"
else -> "mock_others"
}
}
}
private val demoService = DemoService()
@ -65,15 +71,21 @@ internal class DemoServiceTest {
@Test
fun should_able_to_get_source_method_name() {
assertEquals("mock_one_mock_others", demoService.callerTwo() + "_" + demoService.callerOne())
assertEquals("mock_one_mock_others", Callable<String> {
// synchronous
assertEquals("mock_one_mock_others", demoService.callerOne() + "_" + demoService.callerTwo())
// asynchronous
assertEquals("mock_one_mock_others", Executors.newSingleThreadExecutor().submit<String> {
demoService.callerOne() + "_" + demoService.callerTwo()
}.call())
}.get())
}
@Test
fun should_able_to_get_test_case_name() {
assertEquals("should_able_to_get_test_case_name", TEST_CASE)
assertEquals("should_able_to_get_test_case_name", Callable<String> { TEST_CASE }.call())
// synchronous
assertEquals("mock_special", demoService.callerOne())
// asynchronous
assertEquals("mock_special", Executors.newSingleThreadExecutor().submit<String> {
demoService.callerOne()
}.get())
}
}