Mockito调用测试方法使用多参数匹配器报错,求解决方案
嘿,我知道你被这个报错搞懵了——毕竟前三种写法都没问题,怎么全用匹配器就炸了?别着急,咱们来拆解一下问题根源:
核心问题:你用错了Mockito匹配器的场景
Mockito的anyString()、anyInt()这类参数匹配器,只能用在Mockito自己的API里(比如when()或者verify()),绝对不能直接拿来当参数传给你要测试的真实方法(也就是areaService.addAreaToDB())。
为啥前三种没报错?
其实严格来说,你第二种和第三种写法(比如areaService.addAreaToDB(anyString(), areaCode))本身也是不符合规则的,只是因为你的测试逻辑没触发Mockito的严格检查,才侥幸没报错。但这些写法本质上是错误的,只是没被揪出来而已。
第四种为啥炸了?
当你写areaService.addAreaToDB(anyString(), anyInt())的时候,你把两个匹配器直接传给了被测试方法。Mockito的匹配器是靠线程本地存储来工作的,只有在when()或verify()的上下文里才有效。这时候你不在Mockito的API调用里用匹配器,它就会混乱,以为你在设置某个mock的预期,但又找不到对应的目标,所以就抛出了那个“期望1个匹配器,却记录了2个”的错误。
正确的打开方式
如果你想测试方法在任意参数下的表现,应该传具体的测试值,而不是匹配器。举个例子:
@Test public void testAddAreaToDB() { // 准备测试用的具体参数 String testAreaName = "测试区域"; Integer testAreaCode = 123; // 设置mock行为:当查询该区域编码时返回null(表示不存在) when(areaDao.getByAreaCode(anyInt())).thenReturn(null); // 调用被测试方法,传具体值 boolean result = areaService.addAreaToDB(testAreaName, testAreaCode); // 验证结果和后续行为 Assert.assertTrue(result); // 这里才是匹配器的正确用法:验证save方法被调用,参数是任意Area对象 verify(areaDao).save(any(Area.class)); verify(onlineDiskService).initFoldersAndPrime(testAreaCode); }
如果要覆盖多种参数情况,用TestNG的@DataProvider做参数化测试就好,比瞎用匹配器靠谱多了:
@DataProvider(name = "areaTestParams") public Object[][] getAreaParams() { return new Object[][] { {"北京", 100000}, {"上海", 200000}, {"", 0} // 测试空名称和0编码的场景 }; } @Test(dataProvider = "areaTestParams") public void testAddAreaToDBWithDifferentParams(String areaName, Integer areaCode) { when(areaDao.getByAreaCode(areaCode)).thenReturn(null); boolean result = areaService.addAreaToDB(areaName, areaCode); Assert.assertTrue(result); verify(areaDao).save(new Area(areaCode, areaName)); verify(onlineDiskService).initFoldersAndPrime(areaCode); }
最后再划个重点:匹配器只能用在when()和verify()里,别拿来给真实方法传参!这样就能彻底避开这个坑啦。
内容的提问来源于stack exchange,提问作者Amos Sun

