繁体   English   中英

Mockito - thenReturn 总是返回 null object

[英]Mockito - thenReturn always returns null object

我正在尝试实现 Mockito 来测试特定方法,但是 the.thenReturn(...) 似乎总是返回 null object 而不是我想要的:

切:

public class TestClassFacade {

  // injected via Spring
  private InterfaceBP bpService;

  public void setBpService(InterfaceBP bpService) {

      this.bpService = bpService;
  }

  public TestVO getTestData(String testString) throws Exception {

    BPRequestVO bpRequestVO = new BPRequestVO();

    bpRequestVO.setGroupNumber(testString) ;
    bpRequestVO.setProductType("ALL") ;           
    bpRequestVO.setProfileType("Required - TEST") ;

    IBPServiceResponse serviceResponse = bpService.getProduct(bpRequestVO);  //PROBLEM

    if (serviceResponse.getMessage().equalsIgnoreCase("BOB")) {

        throw new Exception();

    } else {

        TestVO testVO = new TestVO();
    }

    return testVO;
  }

}

Spring 配置:

<bean id="testClass" class="com.foo.TestClassFacade">

   <property name="bpService" ref="bpService" />

</bean>

<bean id="bpService" class="class.cloud.BPService" />

Mockito 测试方法:

@RunWith(MockitoJUnitRunner.class)
public class BaseTest {

    @Mock BPService mockBPService;
    @InjectMocks TestClassFacade mockTestClassFacade;

    private String testString = null;
    private BPRequestVO someBPRequestVO = new BPRequestVO();
    private IBPServiceResponse invalidServiceResponse = new BPServiceResponse();

    @Test (expected = Exception.class)
    public void getBPData_bobStatusCode_shouldThrowException() throws Exception {

        invalidServiceResponse.setMessage("BOB");

        someBPRequestVO.setGroupNumber(null);
        someBPRequestVO.setProductType("ALL");
        someBPRequestVO.setProfileType("Required - TEST");

        System.out.println("1: " + someBPRequestVO.getGroupNumber());
        System.out.println("2: " + someBPRequestVO.getProductType());
        System.out.println("3: " + someBPRequestVO.getProfileType());
        System.out.println("4: " + someBPRequestVO.getEffectiveDate());

        when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);

        mockTestClassFacade.getTestData(testString);

        verify(mockBPService).getProduct(someBPRequestVO);
    }
}

系统 output:

1: null
2: ALL
3: Required - TEST
4: null

这里发生的事情是,当我运行测试时,serviceResponse object 在上面标有 //PROBLEM 的 CUT 中的行上是 null。 我的愿望是用我的测试方法中的“invalidServiceResponse”object 填充 object。 从我的 System.out.println 的 output 来看,我的 bpRequestVO 在内容上与我的 someBPRequestVO 匹配。

有人可以告诉我我在这里缺少什么吗?

谢谢你的时间!

您在when()使用的 BPRequestVO 实例与在getTestData()使用的实例不同。
除非您覆盖equals() ,否则它们将不匹配。

如果覆盖 equals(),则不需要编写自定义匹配器。 请注意Mockito 文档中的以下内容

“自定义参数匹配器可以降低测试的可读性。有时最好为传递给模拟的参数实现 equals()(Mockito 自然使用 equals() 进行参数匹配)。这可以使测试更清晰。”

您可以使用“any(YourObject.class)”创建一个模拟参数,而不是在您的 BPRequestVO 类中创建一个 equals 方法,如下所示:

when(mockBPService.getProduct(any(BPRequestVO.class))).thenReturn(invalidServiceResponse);

问题在于您对when()

您提交对构造实例的引用; 因此,只有当传递给方法的参数与引用相同时,模拟才会返回您想要的内容。

你想要的是一个参数匹配器; 就像是:

when(mockBPService.getProduct(argThatMatches(someBPRequestVO))
    .thenReturn(whatYouWant);

当然,它需要你编写参数匹配器!

请注意,有一个内置匹配器可以执行您想要的操作:

when(mockBPService.getProduct(eq(someBPRequestVO))).thenReturn(whatYouWant);

这个匹配器当然需要你的BPRequestVO类实现equals() (和hashCode()太)!

我的问题是模拟服务被定义为最终的。

用于模拟的 BPRequestVO 对象实例与 junit 执行时使用的实例不同。

最好的方法是在模拟时配置对象的任何实例

when(mockBPService.getProduct(someBPRequestVO)).thenReturn(invalidServiceResponse);

可以更新为

when(mockBPService.getProduct(Mockito.any(BPRequestVO.class))).thenReturn(invalidServiceResponse);

我的问题是传递 null 作为方法参数与我设置的 when() 子句不匹配。

例如

Car car = mock(Car.class)
when(car.start(anyString()).thenReturn("vroom");
assertEquals("vroom", car.start(null));

这会失败。

assertEquals("vroom", car.start("Now"));

这通过。

我的问题是自动装配/模拟bean 的服务实例在 Test->given() 部分有不同的实例,而在执行时它有不同的实例。

这是通过在调试模式下运行测试并检查模拟存根和执行代码中的每个值发现的。 如果所有参数和模拟实例都相同,那么只有 thenReturn() 将返回预期值。

在 myscenario 中,类的模拟实例有多个实现,通过添加 @Qualifier("name") 实例在 given() 和实际执行中变得相同。

它也可能发生在多线程的情况下。 在 @Test 方法返回后,模拟对象的处理程序被 mockito 重置,而某处(另一个线程)仍在使用模拟的 object。

对于池提供Thread的情况,可以mock一个线程池代替,在当前Thread中执行Runner.run()证明是有效的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM