如果我们在方法内部调用私有方法,如何模拟或准备测试方法?
How to mock or prepare test methods in case we called private method inside the method?
在为Controllerclass编写测试用例时,私有方法getServiceContext()。有不同的对象,因为
一个我们从 testclass 传递 serviceContext 和控制器内部的其他对象 class 本身调用 itself.Due 到这个 Foo 对象是空的。如何解决这个问题。
public class 控制器 {
@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;
}
}
public class 控制器测试 {
@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();
}
}
有多种方法可以做到这一点。
首先,我们可以使用 anyOf(Type.class)
进行模拟,这将实际匹配对象类型而不是值。
Mockito
.when(fooService.getFoo(Mockit.eq("testId"), Mockito.any(ServiceContext.class)))
.thenReturn(foo);
这将按预期工作,return 所需的值。
此外,如果你想检查 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()
returns 正在传递的服务上下文对象。因此,您可以验证该对象中要验证的所有数据。
替代,方法是Spy
,它基本上会监视被测class,您可以控制测试中私有方法的行为class本身。
为此,我们需要在测试 class.
上添加 @Spy
注释和 @InjectMocks
@Spy
@InjectMocks
private Controller controller;
现在,您可以模拟私有方法和 return 预期值。
Mockito.doReturn(serviceContextValue).when(controller).getServiceContext();
并使用该对象进行模拟 fooService
。
Mockito.verify(fooService).getFoo("testId", serviceContextValue);
但是当使用Spy
时,不要忘记为私有方法编写单元测试,因为它被模拟了,它的业务逻辑不会被上述测试用例测试。这是一个原因,不推荐这种方式。
我建议使用 ArgumentCaptor
方法。
在为Controllerclass编写测试用例时,私有方法getServiceContext()。有不同的对象,因为 一个我们从 testclass 传递 serviceContext 和控制器内部的其他对象 class 本身调用 itself.Due 到这个 Foo 对象是空的。如何解决这个问题。
public class 控制器 {
@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;
}
}
public class 控制器测试 {
@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();
}
}
有多种方法可以做到这一点。
首先,我们可以使用 anyOf(Type.class)
进行模拟,这将实际匹配对象类型而不是值。
Mockito
.when(fooService.getFoo(Mockit.eq("testId"), Mockito.any(ServiceContext.class)))
.thenReturn(foo);
这将按预期工作,return 所需的值。
此外,如果你想检查 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()
returns 正在传递的服务上下文对象。因此,您可以验证该对象中要验证的所有数据。
替代,方法是Spy
,它基本上会监视被测class,您可以控制测试中私有方法的行为class本身。
为此,我们需要在测试 class.
上添加@Spy
注释和 @InjectMocks
@Spy
@InjectMocks
private Controller controller;
现在,您可以模拟私有方法和 return 预期值。
Mockito.doReturn(serviceContextValue).when(controller).getServiceContext();
并使用该对象进行模拟 fooService
。
Mockito.verify(fooService).getFoo("testId", serviceContextValue);
但是当使用Spy
时,不要忘记为私有方法编写单元测试,因为它被模拟了,它的业务逻辑不会被上述测试用例测试。这是一个原因,不推荐这种方式。
我建议使用 ArgumentCaptor
方法。