【问题标题】:How to mock or prepare test methods in case we called private method inside the method?如果我们在方法内部调用私有方法,如何模拟或准备测试方法?
【发布时间】:2020-05-26 15:30:02
【问题描述】:

在为Controller类编写测试用例时,私有方法getServiceContext()。有不同的对象,因为 我们从 testclass 传递 serviceContext 和控制器类中的其他对象本身调用自身。由于这个 Foo 对象为空。如何解决这个问题。

公共类控制器{

@Refernce
private FooService fooService;

public CustomData getDetails(String id){

      Foo foo = fooService.getFoo(id ,**getServiceContext()**); 
         //getServiceContext() is different object
    System.out.println("foo data>>>> "+foo); // **Throwing null pointer exceptions** 

      CustomData customData = new CustomData();
      customData.setStudentName(foo.getName);
      customData.setStudentName(foo.getId);
      ...
      ...
      ...
    return  customData;

}

private ServiceContext getServiceContext() {

 ServiceContext serviceContext = new ServiceContext();
    serviceContext.setCompanyId(context..);
    serviceContext.setUserId(context..);
    ...
    ....    
retrn serviceContext;

}

}


公共类 ControllerTest {

@InjectMocks
private Controller controller;

@Mock
private FooService fooService;

private Foo foo;

@BeforeEach
public void setUp() throws PortalException {

foo = mock(Foo.class);

}

@Test
public void getDetailsTest() throws Exception {

    ServiceContext **serviceContext** = new ServiceContext();
    serviceContext.setCompanyId(context..);
    serviceContext.setUserId(context..);
    ...
    ....    
    Mockito.when(fooService.getFoo("testId",serviceContext)).thenReturn(foo);

    System.out.println("Service context>>>> "+**serviceContext**); // different serviceContext object
    CustomData customData = controller.getDetails("testId");

    Assertions.assertThat(ss).isNotNull();
}

}

【问题讨论】:

    标签: mockito junit5 liferay-7 junit-jupiter


    【解决方案1】:

    有多种方法可以做到这一点。

    首先,我们可以使用anyOf(Type.class) 进行模拟,这实际上将匹配对象类型而不是值。

    Mockito
     .when(fooService.getFoo(Mockit.eq("testId"), Mockito.any(ServiceContext.class)))
     .thenReturn(foo);
    

    这将按预期工作并返回所需的值。

    此外,如果您想检查 serviceContext 对象在服务方法中作为 arg 传递的数据(因为我们只是检查对象类型而不是值),我们可以使用 ArgumentCaptor

    它基本上捕获在方法调用中传递的参数数据。

    让我们为服务上下文创建 ArgumentCaptor

    @Mock
    private FooService fooService;
    
    @Captor
    private ArgumentCaptor<ServiceContext> captor;
    

    现在,让我们在验证期间捕获参数。

    Mockito.verify(fooService).getFoo(Mockit.eq("testId"), captor.capture());
    
    Assertions.assertEquals("value of x in context", captor.getValue().getX());
    

    基本上在这里,captor.getValue() 返回正在传递的服务上下文对象。因此,您可以验证要在该对象中验证的所有数据。

    替代,方法是Spy,它基本上会监视被测类,您可以控制测试类本身中私有方法的行为。

    为此,我们需要在测试类上添加@Spy 注释和@InjectMocks

    @Spy
    @InjectMocks
    private Controller controller;
    

    现在,您可以模拟私有方法并返回预期值。

    Mockito.doReturn(serviceContextValue).when(controller).getServiceContext();
    

    并使用该对象模拟fooService

    Mockito.verify(fooService).getFoo("testId", serviceContextValue);
    

    但是在使用Spy时,不要忘记为私有方法编写单元测试,因为它是模拟的,它的业务逻辑不会被上述测试用例测试。这是一个原因,不推荐的方式。

    我建议使用ArgumentCaptor 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多