单元测试 - Mockito - 如何模拟/验证接受新对象的方法调用



我有一个方法(method1)我想测试,它根据提供的参数创建一个对象并调用另一个方法(method2)。所以我在模拟方法2,它接受一个对象(sampleObj)。

public void method1(booleanParam) {
    if(booleanParam){
        List<SampleObj> fooList = new ArrayList<SampleObj>;
        fooList.add(new SampleObj("another param"));
        anotherService.method2(fooList);
    }
    //some other smart logic here
}

这是我使用相同的混淆名称的测试(抱歉,如果我错过了任何拼写错误):

public void testMethod1() {
    AnotherService mockedAnotherService = PowerMockito.mock(AnotherService.class);
    ServicesFactory.getInstance().setMock(AnotherService.class, mockedAnotherService);
    List<SampleObj> fooList = new ArrayList<SampleObj>;
    fooList.add(new SampleObj("another param"));
    // assert and verify
    service.method1(true);
    Mockito.verify(mockedAnotherService, times(1)).method2(fooList);
}

问题是,当我尝试模拟另一个服务时,我需要将一个对象传递给 method2,所以我必须创建一个新对象。但由于它是一个新对象,它不是同一个对象,它将从 method1 内部传递,因此测试失败并出现异常:

Argument(s) are different! Wanted:
anotherService.method2(
    [com.smart.company.SampleObj@19c59e46]
);
-> at <test filename and line # here>
Actual invocation has different arguments:
anotherService.method2(
    [com.smart.company.SampleObj@7d1a12e1]
);
-> at <service filename and line # here>

有什么想法吗?

您有几个选择:

  1. SampleObj上实施equalshashCode。由于您没有将fooList包装在匹配器中,因此 Mockito 会检查 List.equals ,这会检查每个列表中是否有相应的对象equals。Object.equals 的默认行为是 a.equals(b) iff a == b - 也就是说,对象是相等的,如果它们引用相同的实例 - 但如果每个 SampleObj("foobar") 等于每个其他 SampleObj("foobar"),欢迎您覆盖它。

  2. 使用您编写的Hamcrest Matcher。

    private static Matcher<List<SampleObj>> isAListWithObjs(String... strings) {
      return new AbstractMatcher<List<SampleObj>>() {
        @Override public boolean matches(Object object) {
          // return true if object is a list of SampleObj corresponding to strings
        }
      };
    }
    // in your test
    verify(mockedAnotherService).method2(argThat(isAnObjListWith("another param")));
    

    请注意,您也可以只制作单个 SampleObj 的匹配器,然后使用 Hamcrest 包装器,如 hasItem 。在此处查看更多匹配器。

  3. 使用捕获者以您自己的方式检查equals

    public class YourTest {
      // Populated with MockitoAnnotations.initMocks(this).
      // You can also use ArgumentCaptor.forClass(...), but with generics trouble.
      @Captor ArgumentCaptor<List<SampleObj>> sampleObjListCaptor;
      @Test public void testMethod1() {
        // ...
        verify(mockedAnotherService).method2(sampleObjListCaptor.capture());
        List<SampleObj> sampleObjList = sampleObjListCaptor.getValue();
        assertEquals(1, sampleObjList.size());
        assertEquals("another param", sampleObjList.get(0).getTitle());
      }
    

相关内容

  • 没有找到相关文章

最新更新