support mocking invocation inside an inner class

This commit is contained in:
金戟 2021-03-04 23:41:22 +08:00
parent b163152c2f
commit 121536a337
6 changed files with 181 additions and 6 deletions

View File

@ -0,0 +1,60 @@
package com.alibaba.demo.basic;
import java.util.concurrent.*;
/**
* 演示对内部类的Mock支持
* Demonstrate support for mocking invocation inside a inner class
*/
public class DemoInnerClass {
public static class StaticInner {
/**
* invocation inside a static inner class
*/
public String demo() {
return methodToBeMock();
}
}
public class Inner {
/**
* invocation inside a non-static inner class
*/
public String demo() {
return methodToBeMock();
}
}
private ExecutorService executorService = Executors.newSingleThreadExecutor();
public String callAnonymousInner() throws ExecutionException, InterruptedException {
/**
* invocation inside a anonymous inner class
*/
Future<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return methodToBeMock();
}
});
return future.get();
}
public String callLambdaInner() throws ExecutionException, InterruptedException {
/**
* invocation inside a lambda inner class
*/
Future<String> future = executorService.submit(() -> methodToBeMock());
return future.get();
}
public String callInnerDemo() {
return new Inner().demo();
}
public static String methodToBeMock() {
return "RealCall";
}
}

View File

@ -0,0 +1,29 @@
package com.alibaba.demo.basic;
import com.alibaba.testable.core.annotation.MockMethod;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* 演示对内部类的Mock支持
* Demonstrate support for mocking invocation inside a inner class
*/
class DemoInnerClassTest {
public static class Mock {
@MockMethod(targetClass = DemoInnerClass.class)
String methodToBeMock() {
return "MockedCall";
}
}
@Test
void should_able_to_mock_invoke_inside_inner_class() throws Exception {
DemoInnerClass demo = new DemoInnerClass();
assertEquals("MockedCall", demo.callInnerDemo());
assertEquals("MockedCall", demo.callAnonymousInner());
assertEquals("MockedCall", demo.callLambdaInner());
assertEquals("MockedCall", new DemoInnerClass.StaticInner().demo());
}
}

View File

@ -0,0 +1,49 @@
package com.alibaba.demo.basic
import java.util.concurrent.ExecutionException
import java.util.concurrent.Executors
/**
* 演示对内部类的Mock支持
* Demonstrate support for mocking invocation inside a inner class
*/
class DemoInnerClass {
class StaticInner {
/**
* invocation inside a static inner class
*/
fun demo(): String {
return methodToBeMock()
}
}
inner class Inner {
/**
* invocation inside a non-static inner class
*/
fun demo(): String {
return methodToBeMock()
}
}
private val executorService = Executors.newSingleThreadExecutor()
@Throws(ExecutionException::class, InterruptedException::class)
fun callAnonymousInner(): String {
/**
* invocation inside a anonymous inner class
*/
val future = executorService.submit<String> { methodToBeMock() }
return future.get()
}
fun callInnerDemo(): String {
return Inner().demo()
}
companion object {
fun methodToBeMock(): String {
return "RealCall"
}
}
}

View File

@ -0,0 +1,28 @@
package com.alibaba.demo.basic
import com.alibaba.testable.core.annotation.MockMethod
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
/**
* 演示对内部类的Mock支持
* Demonstrate support for mocking invocation inside a inner class
*/
internal class DemoInnerClassTest {
class Mock {
@MockMethod(targetClass = DemoInnerClass::class)
fun methodToBeMock(): String {
return "MockedCall"
}
}
@Test
@Throws(Exception::class)
fun should_able_to_mock_invoke_inside_inner_class() {
val demo = DemoInnerClass()
Assertions.assertEquals("MockedCall", demo.callInnerDemo())
Assertions.assertEquals("MockedCall", demo.callAnonymousInner())
Assertions.assertEquals("MockedCall", DemoInnerClass.StaticInner().demo())
}
}

View File

@ -111,7 +111,16 @@ public class TestableClassTransformer implements ClassFileTransformer {
if (mockClass != null) {
return mockClass;
}
return foundMockForTestClass(ClassUtil.getTestClassName(className));
mockClass = foundMockForTestClass(ClassUtil.getTestClassName(className));
if (mockClass != null) {
return mockClass;
}
return foundMockForInnerSourceClass(className);
}
private String foundMockForInnerSourceClass(String className) {
return (className.contains(DOLLAR) && !className.endsWith(KOTLIN_POSTFIX_COMPANION)) ?
foundMockForTestClass(ClassUtil.getTestClassName(className.substring(0, className.indexOf(DOLLAR)))) : null;
}
private String foundMockForTestClass(String className) {

View File

@ -41,11 +41,11 @@ class MethodUtilTest {
@Test
void should_able_to_convert_bytecode_parameters() {
assertEquals("", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", ""));
assertEquals("char", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "C"));
assertEquals("int,long", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "IJ"));
assertEquals("int[],long[]", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "[I[J"));
assertEquals("int,java.lang.String", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "ILjava/lang/String;"));
assertEquals("java.lang.String,int,long[]", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "Ljava/lang/String;I[J"));
assertEquals("void", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "V"));
assertEquals("int, long", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "IJ"));
assertEquals("int[], long[]", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "[I[J"));
assertEquals("int, java.lang.String", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "ILjava/lang/String;"));
assertEquals("java.lang.String, int, long[]", PrivateAccessor.invokeStatic(MethodUtil.class, "toJavaParameterDesc", "Ljava/lang/String;I[J"));
}
}