add test case for matchers

This commit is contained in:
金戟 2020-11-16 21:00:10 +08:00
parent 525e252f96
commit 43cd4aeeec
3 changed files with 178 additions and 17 deletions

View File

@ -0,0 +1,71 @@
package com.alibaba.testable.demo.service;
import com.alibaba.testable.demo.model.BlackBox;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
/**
* @author flin
*/
@Service
public class DemoMatcherService {
/**
* Method to be mocked
*/
private void methodToBeMocked() {
// pretend to have some code here
}
/**
* Method to be mocked
*/
private void methodToBeMocked(Object a1, Object a2) {
// pretend to have some code here
}
/**
* Method to be mocked
*/
private void methodToBeMocked(Object[] a) {
// pretend to have some code here
}
public void callMethodWithoutArgument() {
methodToBeMocked();
}
public void callMethodWithNumberArguments() {
// named variable and lambda variable will be recorded as different type
// should have them both in test case
List<Float> floatList = new ArrayList<>();
floatList.add(1.0F);
floatList.add(2.0F);
methodToBeMocked(1, 2);
methodToBeMocked(1L, 2.0);
Long[] longArray = new Long[]{1L, 2L};
methodToBeMocked(new ArrayList<Integer>(){{ add(1); }}, new HashSet<Float>(){{ add(1.0F); }});
methodToBeMocked(1.0, new HashMap<Integer, Float>(2){{ put(1, 1.0F); }});
methodToBeMocked(floatList, floatList);
methodToBeMocked(longArray);
methodToBeMocked(new Double[]{1.0, 2.0});
}
public void callMethodWithStringArgument() {
methodToBeMocked("hello", "world");
methodToBeMocked("testable", "mock");
methodToBeMocked(new String[]{"demo"});
}
public void callMethodWithObjectArgument() {
methodToBeMocked(new BlackBox("hello"), new BlackBox("world"));
methodToBeMocked(new BlackBox("demo"), null);
methodToBeMocked(null, new BlackBox("demo"));
}
}

View File

@ -0,0 +1,61 @@
package com.alibaba.testable.demo.service;
import com.alibaba.testable.core.annotation.TestableMock;
import com.alibaba.testable.demo.model.BlackBox;
import org.junit.jupiter.api.Test;
import static com.alibaba.testable.core.matcher.InvokeMatcher.*;
import static com.alibaba.testable.core.tool.TestableTool.*;
class DemoMatcherServiceTest {
private DemoMatcherService demo = new DemoMatcherService();
@TestableMock(targetMethod = "methodToBeMocked")
private void methodWithoutArgument(DemoMatcherService self) {}
@TestableMock(targetMethod = "methodToBeMocked")
private void methodWithArguments(DemoMatcherService self, Object a1, Object a2) {}
@TestableMock(targetMethod = "methodToBeMocked")
private void methodWithArrayArgument(DemoMatcherService self, Object[] a) {}
@Test
void should_match_no_argument() {
demo.callMethodWithoutArgument();
verify("methodWithoutArgument").withTimes(1);
demo.callMethodWithoutArgument();
verify("methodWithoutArgument").withTimes(2);
}
@Test
void should_match_number_arguments() {
demo.callMethodWithNumberArguments();
verify("methodWithArguments").without(anyString(), 2);
verify("methodWithArguments").withInOrder(anyInt(), 2);
verify("methodWithArguments").withInOrder(anyLong(), anyNumber());
verify("methodWithArguments").with(1.0, anyMapOf(Integer.class, Float.class));
verify("methodWithArguments").with(anyList(), anySetOf(Float.class));
verify("methodWithArguments").with(anyList(), anyListOf(Float.class));
verify("methodWithArrayArgument").with(anyArrayOf(Long.class));
verify("methodWithArrayArgument").with(anyArray());
}
@Test
void should_match_string_arguments() {
demo.callMethodWithStringArgument();
verify("methodWithArguments").with(startsWith("he"), endsWith("ld"));
verify("methodWithArguments").with(contains("stab"), matches("m.[cd]k"));
verify("methodWithArrayArgument").with(anyArrayOf(String.class));
}
@Test
void should_match_object_arguments() {
demo.callMethodWithObjectArgument();
verify("methodWithArguments").withInOrder(any(BlackBox.class), any(BlackBox.class));
verify("methodWithArguments").withInOrder(nullable(BlackBox.class), nullable(BlackBox.class));
verify("methodWithArguments").withInOrder(isNull(), notNull());
}
}

View File

@ -97,7 +97,7 @@ public class InvokeMatcher {
}
public static InvokeMatcher anyListOf(final Class<?> clazz) {
return anyClassWithTemplateOf(List.class, clazz);
return anyClassWithCollectionOf(List.class, clazz);
}
public static InvokeMatcher anySet() {
@ -105,7 +105,7 @@ public class InvokeMatcher {
}
public static InvokeMatcher anySetOf(final Class<?> clazz) {
return anyClassWithTemplateOf(Set.class, clazz);
return anyClassWithCollectionOf(Set.class, clazz);
}
public static InvokeMatcher anyMap() {
@ -113,16 +113,7 @@ public class InvokeMatcher {
}
public static InvokeMatcher anyMapOf(final Class<?> keyClass, final Class<?> valueClass) {
return any(new MatchFunction() {
@Override
public boolean check(Object value) {
return value != null &&
Map.class.isAssignableFrom(value.getClass()) &&
value.getClass().getTypeParameters().length == 2 &&
keyClass.isAssignableFrom(value.getClass().getTypeParameters()[0].getGenericDeclaration()) &&
valueClass.isAssignableFrom(value.getClass().getTypeParameters()[1].getGenericDeclaration());
}
});
return anyClassWithMapOf(keyClass, valueClass);
}
public static InvokeMatcher anyCollection() {
@ -130,7 +121,7 @@ public class InvokeMatcher {
}
public static InvokeMatcher anyCollectionOf(final Class<?> clazz) {
return anyClassWithTemplateOf(Collection.class, clazz);
return anyClassWithCollectionOf(Collection.class, clazz);
}
public static InvokeMatcher anyIterable() {
@ -138,7 +129,7 @@ public class InvokeMatcher {
}
public static InvokeMatcher anyIterableOf(final Class<?> clazz) {
return anyClassWithTemplateOf(Iterable.class, clazz);
return anyClassWithCollectionOf(Iterable.class, clazz);
}
public static InvokeMatcher any(final Class<?> clazz) {
@ -248,15 +239,53 @@ public class InvokeMatcher {
});
}
private static InvokeMatcher anyClassWithTemplateOf(final Class<?> collectionClass, final Class<?> clazz) {
private static InvokeMatcher anyClassWithCollectionOf(final Class<?> collectionClass, final Class<?> clazz) {
return any(new MatchFunction() {
@Override
public boolean check(Object value) {
return value != null &&
collectionClass.isAssignableFrom(value.getClass()) &&
value.getClass().getTypeParameters().length == 1 &&
clazz.isAssignableFrom(value.getClass().getTypeParameters()[0].getGenericDeclaration());
allElementsHasType((Collection<?>)value, clazz);
}
});
}
private static InvokeMatcher anyClassWithMapOf(final Class<?> keyClass, final Class<?> valueClass) {
return any(new MatchFunction() {
@Override
public boolean check(Object value) {
return value != null &&
Map.class.isAssignableFrom(value.getClass()) &&
allElementsHasType((Map<?, ?>)value, keyClass, valueClass);
}
});
}
/**
* Because of type erase, there's no way to directly fetch original type of collection template
* this could be a temporary solution
*/
private static boolean allElementsHasType(Map<?, ?> items, Class<?> keyClass, Class<?> valueClass) {
for (Map.Entry<?, ?> e : items.entrySet()) {
if (!(keyClass.isAssignableFrom(e.getKey().getClass()) &&
valueClass.isAssignableFrom(e.getValue().getClass()))) {
return false;
}
}
return true;
}
/**
* Because of type erase, there's no way to directly fetch original type of collection template
* this could be a temporary solution
*/
private static boolean allElementsHasType(Collection<?> values, Class<?> clazz) {
for (Object v : values.toArray()) {
if (!clazz.isAssignableFrom(v.getClass())) {
return false;
}
}
return true;
}
}