mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-02-15 14:20:07 +08:00
support mock invoke by interface instance
This commit is contained in:
parent
36136e878e
commit
ae134ac5ce
@ -1,14 +1,19 @@
|
|||||||
package com.alibaba.testable.demo;
|
package com.alibaba.testable.demo;
|
||||||
|
|
||||||
public class BlackBox {
|
public class BlackBox implements Box {
|
||||||
|
|
||||||
private String data;
|
private String data;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(String something) {
|
||||||
|
data = something;
|
||||||
|
}
|
||||||
|
|
||||||
public BlackBox(String data) {
|
public BlackBox(String data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String callMe() {
|
public String get() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.alibaba.testable.demo;
|
||||||
|
|
||||||
|
public interface Box {
|
||||||
|
|
||||||
|
void put(String something);
|
||||||
|
|
||||||
|
}
|
@ -30,7 +30,7 @@ public class DemoService {
|
|||||||
*/
|
*/
|
||||||
public String newFunc() {
|
public String newFunc() {
|
||||||
BlackBox component = new BlackBox("something");
|
BlackBox component = new BlackBox("something");
|
||||||
return component.callMe();
|
return component.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +54,18 @@ public class DemoService {
|
|||||||
return BlackBox.secretBox();
|
return BlackBox.secretBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target 7 - method with override method invoke
|
||||||
|
*/
|
||||||
|
public Box putBox() {
|
||||||
|
Box box = new BlackBox("");
|
||||||
|
box.put("data");
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target 8 - two methods invoke same private method
|
||||||
|
*/
|
||||||
public String callerOne() {
|
public String callerOne() {
|
||||||
return callFromDifferentMethod();
|
return callFromDifferentMethod();
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,11 @@ class DemoServiceTest {
|
|||||||
return new BlackBox("not_secret_box");
|
return new BlackBox("not_secret_box");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestableMock
|
||||||
|
private void put(Box self, String something) {
|
||||||
|
self.put("put_" + something + "_mocked");
|
||||||
|
}
|
||||||
|
|
||||||
@TestableMock
|
@TestableMock
|
||||||
private String callFromDifferentMethod(DemoService self) {
|
private String callFromDifferentMethod(DemoService self) {
|
||||||
if (TEST_CASE.equals("should_able_to_get_test_case_name")) {
|
if (TEST_CASE.equals("should_able_to_get_test_case_name")) {
|
||||||
@ -93,10 +98,17 @@ class DemoServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_able_to_mock_static_method() throws Exception {
|
void should_able_to_mock_static_method() throws Exception {
|
||||||
assertEquals("not_secret_box", demoService.getBox().callMe());
|
assertEquals("not_secret_box", demoService.getBox().get());
|
||||||
verify("secretBox").times(1);
|
verify("secretBox").times(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void should_able_to_mock_override_method() throws Exception {
|
||||||
|
BlackBox box = (BlackBox)demoService.putBox();
|
||||||
|
verify("put").times(1);
|
||||||
|
assertEquals("put_data_mocked", box.get());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void should_able_to_get_source_method_name() throws Exception {
|
void should_able_to_get_source_method_name() throws Exception {
|
||||||
// synchronous
|
// synchronous
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package com.alibaba.testable.demo
|
package com.alibaba.testable.demo
|
||||||
|
|
||||||
|
|
||||||
class BlackBox(private val data: String) {
|
class BlackBox(private var data: String) : Box {
|
||||||
|
|
||||||
fun callMe(): String {
|
override fun put(something: String) {
|
||||||
|
data = something
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(): String {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +33,6 @@ class BlackBox(private val data: String) {
|
|||||||
|
|
||||||
object ColorBox {
|
object ColorBox {
|
||||||
fun createBox(color: String, box: BlackBox): BlackBox {
|
fun createBox(color: String, box: BlackBox): BlackBox {
|
||||||
return BlackBox("${color}_${box.callMe()}")
|
return BlackBox("${color}_${box.get()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.alibaba.testable.demo
|
||||||
|
|
||||||
|
interface Box {
|
||||||
|
|
||||||
|
fun put(something: String)
|
||||||
|
|
||||||
|
}
|
@ -29,7 +29,7 @@ class DemoService {
|
|||||||
* Target 3 - method with new operation
|
* Target 3 - method with new operation
|
||||||
*/
|
*/
|
||||||
fun newFunc(): String {
|
fun newFunc(): String {
|
||||||
return BlackBox("something").callMe()
|
return BlackBox("something").get()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,6 +54,18 @@ class DemoService {
|
|||||||
return ColorBox.createBox("Red", BlackBox.secretBox())
|
return ColorBox.createBox("Red", BlackBox.secretBox())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target 7 - method with override method invoke
|
||||||
|
*/
|
||||||
|
fun putBox(): Box {
|
||||||
|
val box: Box = BlackBox("")
|
||||||
|
box.put("data")
|
||||||
|
return box
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target 8 - two methods invoke same private method
|
||||||
|
*/
|
||||||
fun callerOne(): String {
|
fun callerOne(): String {
|
||||||
return callFromDifferentMethod()
|
return callFromDifferentMethod()
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,12 @@ internal class DemoServiceTest {
|
|||||||
|
|
||||||
@TestableMock
|
@TestableMock
|
||||||
private fun createBox(ignore: ColorBox, color: String, box: BlackBox): BlackBox {
|
private fun createBox(ignore: ColorBox, color: String, box: BlackBox): BlackBox {
|
||||||
return BlackBox("White_${box.callMe()}")
|
return BlackBox("White_${box.get()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestableMock
|
||||||
|
private fun put(self: Box, something: String) {
|
||||||
|
self.put("put_" + something + "_mocked")
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestableMock
|
@TestableMock
|
||||||
@ -85,11 +90,18 @@ internal class DemoServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun should_able_to_mock_static_method() {
|
fun should_able_to_mock_static_method() {
|
||||||
assertEquals("White_not_secret_box", demoService.getBox().callMe())
|
assertEquals("White_not_secret_box", demoService.getBox().get())
|
||||||
verify("secretBox").times(1)
|
verify("secretBox").times(1)
|
||||||
verify("createBox").times(1)
|
verify("createBox").times(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun should_able_to_mock_override_method() {
|
||||||
|
val box = demoService.putBox() as BlackBox
|
||||||
|
verify("put").times(1)
|
||||||
|
assertEquals("put_data_mocked", box.get())
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun should_able_to_get_source_method_name() {
|
fun should_able_to_get_source_method_name() {
|
||||||
// synchronous
|
// synchronous
|
||||||
|
@ -19,9 +19,10 @@ public class SourceClassHandler extends BaseClassHandler {
|
|||||||
|
|
||||||
private final List<MethodInfo> injectMethods;
|
private final List<MethodInfo> injectMethods;
|
||||||
private final Set<Integer> invokeOps = new HashSet<Integer>() {{
|
private final Set<Integer> invokeOps = new HashSet<Integer>() {{
|
||||||
add(Opcodes.INVOKESTATIC);
|
|
||||||
add(Opcodes.INVOKESPECIAL);
|
|
||||||
add(Opcodes.INVOKEVIRTUAL);
|
add(Opcodes.INVOKEVIRTUAL);
|
||||||
|
add(Opcodes.INVOKESPECIAL);
|
||||||
|
add(Opcodes.INVOKESTATIC);
|
||||||
|
add(Opcodes.INVOKEINTERFACE);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
public SourceClassHandler(List<MethodInfo> injectMethods) {
|
public SourceClassHandler(List<MethodInfo> injectMethods) {
|
||||||
@ -58,7 +59,7 @@ public class SourceClassHandler extends BaseClassHandler {
|
|||||||
MethodInsnNode node = (MethodInsnNode)instructions[i];
|
MethodInsnNode node = (MethodInsnNode)instructions[i];
|
||||||
String memberInjectMethodName = getMemberInjectMethodName(memberInjectMethodList, node);
|
String memberInjectMethodName = getMemberInjectMethodName(memberInjectMethodList, node);
|
||||||
if (memberInjectMethodName != null) {
|
if (memberInjectMethodName != null) {
|
||||||
// it's a member method and an inject method for it exist
|
// it's a member or static method and an inject method for it exist
|
||||||
int rangeStart = getMemberMethodStart(instructions, i);
|
int rangeStart = getMemberMethodStart(instructions, i);
|
||||||
if (rangeStart >= 0) {
|
if (rangeStart >= 0) {
|
||||||
instructions = replaceMemberCallOps(cn, mn, memberInjectMethodName, instructions,
|
instructions = replaceMemberCallOps(cn, mn, memberInjectMethodName, instructions,
|
||||||
@ -119,11 +120,11 @@ public class SourceClassHandler extends BaseClassHandler {
|
|||||||
int stackLevel = ClassUtil.getParameterTypes(((MethodInsnNode)instructions[rangeEnd]).desc).size();
|
int stackLevel = ClassUtil.getParameterTypes(((MethodInsnNode)instructions[rangeEnd]).desc).size();
|
||||||
for (int i = rangeEnd - 1; i >= 0; i--) {
|
for (int i = rangeEnd - 1; i >= 0; i--) {
|
||||||
switch (instructions[i].getOpcode()) {
|
switch (instructions[i].getOpcode()) {
|
||||||
case Opcodes.INVOKEINTERFACE:
|
|
||||||
case Opcodes.INVOKEVIRTUAL:
|
case Opcodes.INVOKEVIRTUAL:
|
||||||
case Opcodes.INVOKESPECIAL:
|
case Opcodes.INVOKESPECIAL:
|
||||||
case Opcodes.INVOKEDYNAMIC:
|
|
||||||
case Opcodes.INVOKESTATIC:
|
case Opcodes.INVOKESTATIC:
|
||||||
|
case Opcodes.INVOKEINTERFACE:
|
||||||
|
case Opcodes.INVOKEDYNAMIC:
|
||||||
stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size();
|
stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size();
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
|
Loading…
Reference in New Issue
Block a user