Java单元测试实践-00.目录(9万多字文档+700多测试示例)
https://blog.csdn.net/a82514921/article/details/107969340
1. Mockito的Stub参数条件
使用Mockito.when().then…()/Mockito.do…().when()等对方法进行Stub时,需要为每个参数指定Stub条件。以下以静态方法为示例,对Mockito.when()的Stub参数条件进行说明。
1.1. 等于指定值
在使用Mockito.when(被Stub方法所在的类.被Stub方法())指定被Stub方法的条件时,可以指定当参数等于指定值时进行Stub,与Mockito.eq()方法的功能相同。 如下所示,可参考示例TestStPuNVArgsEquals类。
Mockito.when(C1.test1("...", 1)).thenReturn("...");
1.2. 等于指定类型
Mockito类继承自ArgumentMatchers类,在ArgumentMatchers类中包含了很多指定Stub的参数条件的方法。
Stub参数条件可以设置为等于指定的类型,如下所示:
<T> T any(Class<T> type)
boolean anyBoolean()
byte anyByte()
char anyChar()
<T> Collection<T> anyCollection()
<T> Collection<T> anyCollectionOf(Class<T> clazz)
double anyDouble()
float anyFloat()
int anyInt()
<T> Iterable<T> anyIterable()
<T> Iterable<T> anyIterableOf(Class<T> clazz)
<T> List<T> anyList()
<T> List<T> anyListOf(Class<T> clazz)
long anyLong()
<K, V> Map<K, V> anyMap()
<K, V> Map<K, V> anyMapOf(Class<K> keyClazz, Class<V> valueClazz)
<T> Set<T> anySet()
<T> Set<T> anySetOf(Class<T> clazz)
short anyShort()
String anyString()
以上方法代表当调用方法的参数满足对应类型时,Stub条件生效。
any(Class<T> type)方法需要指定对应的Class对象,示例如下。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.any(TestTableEntity.class))).thenReturn
(TestConstants.MOCKED);
当调用参数为null时,不能满足以上any…()方法对应的Stub参数条件。
例如对某方法进行Stub时,Stub参数设置设置为“Mockito.anyString()”,则调用该被Stub的方法时,若调用参数为null,则不满足Stub参数条件,不会执行Stub指定的操作。
可参考示例TestStPuNVArgsAnyType类。
1.3. 等于任意类型
Stub参数条件可以为等于任意类型,如下所示:
<T> T any()
<T> T anyObject()
<T> T anyVararg()
其中anyObject()与anyVararg()方法均为不推荐使用。
使用any()方法代表当调用参数为任意类型时Stub条件均生效, 支持调用参数为null 。示例如下,可参考示例TestStPuNVArgsAny类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.any(), Mockito.any())).thenReturn
(TestConstants.MOCKED);
1.4. 等于指定类型或为null
使用Mockito类的<T> T nullable(Class<T> clazz)方法,可以指定当调用参数为指定类型,或为null时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsNullable类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.nullable(String.class), Mockito.nullable(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
1.5. 等于指定值
Mockito类的eq()方法支持不同类型的参数,包含基本类型与范型,如下所示:
boolean eq(boolean value)
byte eq(byte value)
char eq(char value)
double eq(double value)
float eq(float value)
int eq(int value)
long eq(long value)
short eq(short value)
<T> T eq(T value)
使用eq()方法可以指定当调用参数等于指定值时,Stub条件生效。如下所示,可参考示例TestStPuNVArgsEq类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.eq(TestConstants.FLAG1), Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
1.6. 与指定对象为同一个对象
使用Mockito类的<T> T same(T value)方法,可以指定当调用参数与指定对象为同一个对象时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsSame类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.same(TestConstants.FLAG1), Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
1.7. 与指定对象的成员变量值相同
使用Mockito类的<T> T refEq(T value, String… excludeFields)方法,可以指定当调用参数与指定对象通过反射获取成员变量的值均相同时,Stub条件生效,示例如下:
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.refEq(TestConstants.FLAG1), Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
当被比较对象未实现equals()方法时,可以使用refEq()方法,使用Java Reflection API比较所需对象和实际对象的字段。
Mockito.refEq()方法的参数定义为“T value, String… excludeFields”,通过excludeFields参数可以指定在比较时需要排除的字段名称。示例如下,可参考示例TestStPuNVArgsRefEq类。
TestTableEntity testTableEntity1 = new TestTableEntity();
testTableEntity1.setFlag(TestConstants.FLAG1);
testTableEntity1.setId(TestConstants.FLAG2);
TestTableEntity testTableEntity2 = new TestTableEntity();
testTableEntity2.setFlag(testTableEntity1.getFlag());
testTableEntity2.setId(testTableEntity1.getId() + TestConstants.MINUS);
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.anyString(), Mockito.refEq(testTableEntity1, "id")))
.thenReturn(TestConstants.MOCKED);
String str = TestStaticPublicNonVoid1.test1(TestConstants.FLAG1, testTableEntity2);
assertEquals(TestConstants.MOCKED, str);
1.8. 为空
使用Mockito类的isNull()方法,可以指定当调用参数为空时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsIsNull类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.isNull(), Mockito.isNull())).thenReturn
(TestConstants.MOCKED);
1.9. 非空
使用Mockito类的isNotNull()方法,可以指定当调用参数非空时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsIsNotNull类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.isNotNull(), Mockito.isNotNull())).thenReturn
(TestConstants.MOCKED);
1.10. String类型参数支持的方法
1.10.1. 以指定字符串开头
使用Mockito类的String startsWith(String prefix)方法,可以指定当调用参数为String类型,且以指定字符串开头时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsStrStartsWith类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.startsWith(TestConstants.FLAG1), Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
1.10.2. 以指定字符串结尾
使用Mockito类的String endsWith(String suffix)方法,可以指定当调用参数为String类型,且以指定字符串结尾时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsStrEndsWith类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.endsWith(TestConstants.FLAG1), Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
1.10.3. 包含指定字符串
使用Mockito类的String contains(String substring)方法,可以指定当调用参数为String类型,且包含指定字符串时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsStrContains类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.contains(TestConstants.FLAG1), Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
1.10.4. 满足指定的正则表达式
使用Mockito类的String matches(String regex)或String matches(Pattern pattern)方法,可以指定当调用参数为String类型,且满足指定的正则表达式时,Stub条件生效。示例如下,可参考示例TestStPuNVArgsStrMatches类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.matches("[0-9]{4}"), Mockito.any(TestTableEntity.class)))
.thenReturn(TestConstants.MOCKED);
public static final Pattern pattern1 = Pattern.compile("[0-9]{4}");
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.matches(pattern1), Mockito.any
(TestTableEntity.class))).thenReturn(TestConstants.MOCKED);
1.11. 使用自定义的参数匹配器
Mockito类可以使用自定义参数匹配器的方法如下:
<T> T argThat(ArgumentMatcher<T> matcher)
char charThat(ArgumentMatcher<Character> matcher)
boolean booleanThat(ArgumentMatcher<Boolean> matcher)
byte byteThat(ArgumentMatcher<Byte> matcher)
short shortThat(ArgumentMatcher<Short> matcher)
int intThat(ArgumentMatcher<Integer> matcher)
long longThat(ArgumentMatcher<Long> matcher)
float floatThat(ArgumentMatcher<Float> matcher)
double doubleThat(ArgumentMatcher<Double> matcher)
argThat()方法需要传入类型为ArgumentMatcher<T>的参数,ArgumentMatcher接口在org.mockito包中,提供boolean matches(T argument)方法。
自定义参数匹配器需要实现ArgumentMatcher接口,并指定范型对应的参数,实现matches方法,argument参数代表调用方法时的参数值,在该方法中添加对参数的判断条件,返回true代表参数匹配,返回false代表不匹配。自定义参数匹配器示例如下:
public class TestArgumentMatcherString1 implements ArgumentMatcher<String> {
private static final Logger logger = LoggerFactory.getLogger(TestArgumentMatcherString1.class);
@Override
public boolean matches(String argument) {
logger.info("argument: {}", argument);
return TestConstants.FLAG1.equals(argument);
}
}
使用Mockito.argThat()方法指定自定义参数匹配器的示例如下,可参考示例TestStPuNVArgsArgThat类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.argThat(new TestArgumentMatcherString1()), Mockito
.argThat(new TestArgumentMatcherEntity()))).thenReturn(TestConstants.MOCKED);
1.11.1. 使用匿名类
自定义参数匹配器可以使用匿名类,示例如下,可参考示例TestStPuNVArgsArgThatAnonymous类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.argThat(new ArgumentMatcher<String>() {
@Override
public boolean matches(String argument) {
logger.info("argument: {}", argument);
return TestConstants.FLAG1.equals(argument);
}
}), Mockito.any(TestTableEntity.class))).thenReturn(TestConstants.FLAG1);
1.11.2. 使用lambda表达式设置Stub条件
自定义参数匹配器可以使用lambda表达式,示例如下,可参考示例TestStPuNVArgsArgThatLambda类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.argThat(argument -> {
logger.info("argument: {}", argument);
return TestConstants.FLAG1.equals(argument);
}), Mockito.any(TestTableEntity.class))).thenReturn(TestConstants.MOCKED);
1.11.3. 对方法设置多个自定义参数匹配器
对方法进行Stub,设置多个自定义参数匹配器,当Stub条件不同时,不会相互影响。可参考示例TestStPuNVArgsArgThatMulti类的test1方法。
对方法进行Stub,设置多个自定义参数匹配器,当Stub条件相同时,最后一次设置的Stub生效。可参考示例TestStPuNVArgsArgThatMulti类的test2方法。
1.11.4. 对基本类型使用匹配器
参考Mockito.argThat()方法的说明( https://static.javadoc.io/org.mockito/mockito-core/latest/org/mockito/ArgumentMatchers.html#argThat-org.mockito.ArgumentMatcher- )。需要使用基本类型对应的intThat()、floatThat()方法,避免使用argThat()方法因自动拆箱出现空指针异常。
当使用Mockito.argThat()方法处理基本类型时,会出现NullPointerException异常,且@Test方法执行完毕后会出现失败,提示“Test mechanism.classMethod FAILED”,异常信息提示Mockito.argThat()方法对于匹配器的使用非法,如下所示:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
使用Mockito.argThat()方法处理基本类型示例如下,可参考示例TestStPuNVArgsArgThatPrimitiveWrong类。
Mockito.when(TestStaticPublicNonVoid6.testChar(Mockito.argThat(argument -> argument == TestConstants
.DEFAULT_CHAR))).thenReturn(TestConstants.MOCKED);
当使用Mockito类的charThat()等方法处理对应基本类型的参数时,Stub成功。示例如下,可参考示例TestStPuNVArgsArgThatPrimitiveRight类。
Mockito.when(TestStaticPublicNonVoid6.testChar(Mockito.charThat(argument -> argument == TestConstants
.DEFAULT_CHAR))).thenReturn(TestConstants.MOCKED);
1.12. 参数为数组
当参数为数组时,可以使用Mockito类的any(Class<T> type)或argThat()方法设置Stub条件,示例如下,可参考示例TestStPuNVArgsArray类。
Mockito.when(TestStaticPublicNonVoid1.test8(Mockito.anyString(), Mockito.any(Object[].class))).thenReturn
(TestConstants.MOCKED);
Mockito.when(TestStaticPublicNonVoid1.test8(Mockito.anyString(), Mockito.argThat(argument -> TestConstants
.FLAG1.equals(argument[0])))).thenReturn(TestConstants.MOCKED);
1.13. 参数为范型
当参数为范型时,可以将使用需要的类型设置Stub条件。例如当参数类型为“<T>”时,可使用任意类型设置Stub条件;当参数类型为“<T extends Exception>”时,可使用Exception及子类类型设置Stub条件。可参考示例TestStPuNVArgsTemplate类。
1.14. 变长参数
对于使用变长参数的方法,可以分别设置参数数量不同时的处理,若Stub条件中设置了n个参数,当调用被Stub方法的参数数量为n,且满足每个参数的匹配条件时,Stub才生效。可参考示例TestStPuNVArgsVarArg类的test1方法。
Mockito.any()方法能够匹配任意数量的任意参数。可参考示例TestStPuNVArgsVarArg类的test2方法。
Mockito.any…()、any(Class<T> type)方法只能够匹配一个参数,不能匹配任意数量的参数。可参考示例TestStPuNVArgsVarArg类的test3、test4方法。
1.15. ArgumentMatchers类的方法不能与固定值一起使用
在使用Mockito.when()对某方法进行Stub时,若通过ArgumentMatchers类中的any…()等方法对某参数设置了Stub条件,则其他参数都需要使用ArgumentMatchers类中的方法,不能使用固定值。ArgumentMatchers类的方法与固定值一起使用时会出现异常,示例如下,可参考示例TestStPuNVArgsMix1类。
Mockito.when(TestStaticPublicNonVoid1.test1(TestConstants.FLAG1, Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
异常信息示例如下。
org.mockito.exceptions.misusing.InvalidUseOfMatchersException
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
与ArgumentMatchers类的方法一起使用时,若需要使用固定值,可以使用Mockito.eq()方法指定该参数的Stub条件为等于指定的值。示例如下,可参考示例TestStPuNVArgsMix2类。
Mockito.when(TestStaticPublicNonVoid1.test1(Mockito.eq(TestConstants.FLAG1), Mockito.any(TestTableEntity
.class))).thenReturn(TestConstants.MOCKED);
1.16. Mockito.any(Class type)对于超类及子类的生效情况
当使用Mockito.any(Class<T> type)方法作为Stub条件时,若指定的Stub条件为等于超类,则当参数为超类或子类的对象时,Stub均生效;若指定的Stub条件为等于子类,则当参数为子类的对象时,Stub生效,当参数为超类的对象时,Stub不生效。
例如Stub条件为Mockito.any(Exception.class),则当参数为Exception或RuntimeException类的对象时Stub生效;Stub条件为Mockito.any(RuntimeException.class),则当参数为RuntimeException类的对象时Stub生效,当参数为Exception类的对象时Stub不生效。
可参考示例TestStPuNVArgsSuperClass类。
1.17. 使用Class对象作为参数
对于使用Class对象作为参数的被测试方法,情况如下。
若指定的Stub条件为等于超类,则当参数为超类,Stub均生效,当参数为子类的对象时,Stub不生效;若指定的Stub条件等于为子类,则当参数为子类的对象时,Stub生效,当参数为超类的对象时,Stub不生效。
例如Stub条件为等于Exception.class( 直接指定Exception.class,或Mockito.eq(Exception.class) ),则当参数为Exception.class时Stub生效,当参数为RuntimeException.class时Stub不生效;Stub条件为等于RuntimeException.class,则当参数为RuntimeException.class时Stub生效,当参数为Exception.class时Stub不生效。
可参考示例TestStPuNVArgsClassObject类的test1~test4方法。
若指定的Stub条件为等于或继承自超类,则当参数为超类或子类的对象时,Stub均生效;若指定的Stub条件等于或继承自子类,则当参数为子类的对象时,Stub生效,当参数为超类的对象时,Stub不生效。
例如Stub条件为等于或继承自Exception.class( Mockito.argThat(argument -> Exception.class.isAssignableFrom(argument)) ),则当参数为Exception.class或RuntimeException.class时Stub均生效;Stub条件为等于或继承自RuntimeException.class,则当参数为RuntimeException.class时Stub生效,当参数为Exception.class时Stub不生效。
可参考示例TestStPuNVArgsClassObject类的test5、test6方法。