Mockito 的 anyString(), any(Foo.class) 等不能匹配 null 值
使用 Mockito Mock 方法式,一直以为可以用
说的有点罗嗦,看下面的例子, 被测试类 UserDao,sql 和 sqlArguments 由各自的 setter 方法来控制,默认它们都为
来它的测试类 UserDaoTest
测试不成功,输出信息为
原以为
再执行看到的输出为
查看 ArgumentMatchers.anyString() 的值
似乎
注意,查看它们的值时会有异常,即 reportMatcher 报告出来的。
看起来 ArgumentMatchers.any(MapSqlParameterSource.class) 像是个真的 null 值,所以我们下面只把 anyString() 换成
还是不成功,同样的出错信息
测试通过。eq((MapSqlParameterSource)null) 中的转型是为了避免准确调用重载方法。
最后就是一句话,Mockito 中的
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
anyString(), any(Foo.class) 等匹配 null 值,其实不行,null 值必须显式的用 null, 或 eq(null) 来匹配。anyString(), anyInt() 等只能匹配非 null 值,查看它们的返回值实际是 "" 和 0 等, 而更为特别的是 any(Foo.class) 看到的是 null, 仍然不能匹配 null 值。进一步用 Mockito.mockingDetails(mock).printInvocations() 打印出的内容,anyString(), any(Foo.class) 都会显示为 null 值。说的有点罗嗦,看下面的例子, 被测试类 UserDao,sql 和 sqlArguments 由各自的 setter 方法来控制,默认它们都为
null 1public class UserDao {
2
3 private final NamedParameterJdbcTemplate jdbcTemplate;
4
5 private String sql;
6 private MapSqlParameterSource sqlArguments;
7
8 public void setSql(String sql) {
9 this.sql = sql;
10 }
11
12 public void setSqlArguments(MapSqlParameterSource sqlArguments) {
13 this.sqlArguments = sqlArguments;
14 }
15
16 public UserDao(NamedParameterJdbcTemplate jdbcTemplate) {
17 this.jdbcTemplate = jdbcTemplate;
18 }
19
20 public List<String> fetchUsers() {
21 return jdbcTemplate.query(sql, sqlArguments, (rs, idx) -> rs.getString("name"));
22 }
23}来它的测试类 UserDaoTest
1@RunWith(MockitoJUnitRunner.class)
2public class UserDaoTest {
3
4 @Mock
5 private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
6
7 @InjectMocks
8 private UserDao userDao;
9
10
11 @Test
12 public void testFetchUsers() {
13 when(namedParameterJdbcTemplate.query(anyString(),
14 any(MapSqlParameterSource.class),
15 ArgumentMatchers.<RowMapper<String>>any()))
16 .thenReturn(Arrays.asList("Hello", "Ketty"));
17
18 List<String> users = userDao.fetchUsers();
19 assertThat(users).hasSize(2);
20 }
21}测试不成功,输出信息为
java.lang.AssertionError:空为 Mock 对象
Expected size:<2> but was:<0> in:
<[]>
namedParameterJdbcTemplate.query(...) 方法返回类型的默认值原以为
anyString() 和 any(MapSqlParameterSource.class) 可以匹配到实际中的 sql = null 和 sqlArguments = null 值,都说是 any 却不能对应到 null 值。如果在 assertThat(users).hasSize(2) 之前加上1System.out.println(Mockito.mockingDetails(namedParameterJdbcTemplate).getInvocations());再执行看到的输出为
[namedParameterJdbcTemplate.query(mockingDetails 告诉我们前两个参数的实际值为 null, 不能用
null,
null,
yanbin.blog.UserDao$$Lambda$1/1192672907@363a52f
);]
anyString() 和 any(MapSqlParameterSource.class) 来匹配.查看 ArgumentMatchers.anyString() 的值
1public static String anyString() {
2 reportMatcher(new InstanceOf(String.class, "<any string>"));
3 return "";
4}似乎
anyString() 的值为 "", "" 不能匹配 null 值。断点调试中查看 anyString() 和 any(MapSqlParameterSourcec.class) 的值
注意,查看它们的值时会有异常,即 reportMatcher 报告出来的。看起来 ArgumentMatchers.any(MapSqlParameterSource.class) 像是个真的 null 值,所以我们下面只把 anyString() 换成
eq(null) 来看下 1 @Test
2 public void testFetchUsers() {
3 when(namedParameterJdbcTemplate.query(eq(null),
4 any(MapSqlParameterSource.class),
5 ArgumentMatchers.<RowMapper<String>>any()))
6 .thenReturn(Arrays.asList("Hello", "Ketty"));
7
8 List<String> users = userDao.fetchUsers();
9 assertThat(users).hasSize(2);
10 }还是不成功,同样的出错信息
java.lang.AssertionError:实际运行中的两个 null 都必须用
Expected size:<2> but was:<0> in:
<[]>
null 值来匹配 1 @Test
2 public void testFetchUsers() {
3 when(namedParameterJdbcTemplate.query(eq(null),
4 eq((MapSqlParameterSource)null),
5 ArgumentMatchers.<RowMapper<String>>any()))
6 .thenReturn(Arrays.asList("Hello", "Ketty"));
7
8 List<String> users = userDao.fetchUsers();
9 assertThat(users).hasSize(2);
10 }测试通过。eq((MapSqlParameterSource)null) 中的转型是为了避免准确调用重载方法。
最后就是一句话,Mockito 中的
any 不是真正的 any, any 不代表 null,有点类似 SQLServer 中的某个字段(c1) 的值为 null 时,where c1 is null 可以查出来,但是用 where c1 in (null) 就查不出来了。
永久链接 https://yanbin.blog/mockito-anystring-anyfoo-class-cannot-match-null-values/, 来自 隔叶黄莺 Yanbin's Blog[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。