[英]Unit Test or Mock: Testing Service Class in Spring Boot with Rest Template
我有一个服务 class,为了便于阅读,我为代码提供了虚拟变量和对象。 我正在尝试为该服务编写 JUNIT 测试 class,主要使用 Mockito。 无论我多么努力,无论使用 spy/mock,我都无法使用方法 serviceMethod。 在主要的 class 之后,我还包括了我编写的测试。
测试通过且没有任何错误,但无法从实际的 class 调用该方法。 此后,它不再包含在测试范围内。 (实际 class 中的方法在 Eclipse/SONAR 报告中以红色排除)
我知道我在这里遗漏了一些东西,但我并没有想到。 我需要对此进行审查,并让我知道如何为此编写适当的测试 class 并获得该方法的覆盖率。
(PS 所有必要的导入都是就地的,为了保持简洁,这里没有粘贴)
提前致谢!
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class ServiceClass {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceClass.class);
@Autowired
private Config Config;
@Autowired
private RestTemplate restTemplate;
public void serviceMethod(BusinessClass businessObject) {
String NotificationUrl = Config.getApplicationProperty(businessObject.getCode()).getNotificationUrl();
HttpEntity<StoreNotify> request = new HttpEntity<>(businessObject);
ResponseEntity<String> response = restTemplate.exchange(NotificationUrl, HttpMethod.POST, request,
String.class);
LOGGER.info("Service call, response: {} and status: {} ", response.getBody(),
response.getStatusCode());
}
}
上述测试 Class,
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
@RunWith(MockitoJUnitRunner.Silent.class)
public class ServiceClassTest {
@InjectMocks
private ServiceClass serviceClass;
@Mock
private RestTemplate restTemplate;
@InjectMocks
private BusinessClass businessObject;
@Test
public void testServiceMethod() {
ServiceClass spy = Mockito.spy(serviceClass);
doNothing().when(spy).serviceMethod(businessObject);
spy.serviceMethod(businessObject);
verify(spy, times(1)).serviceMethod(businessObject);
ResponseEntity<String> responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
Mockito.when(restTemplate.exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.<HttpEntity<BusinessClass>>any(), ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
}
}
你可以试试下面的代码。 如果失败,您可能需要进行一些更改,只需评论您的结果,以防下面的代码不起作用。
@RunWith(MockitoJUnitRunner.Silent.class)
public class ServiceClassTest {
@InjectMocks
private ServiceClass serviceClass;
@Mock
private RestTemplate restTemplate;
@Mock
private Config Config;
@Test
public void testServiceMethod() {
BusinessClass businessObject = new BusinessClass();
businessObject.setCode("123"); // set as per your datatype
ResponseEntity<String> responseEntity = new ResponseEntity<>("my String mock body", HttpStatus.ACCEPTED);
Mockito.when(restTemplate.exchange(Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.any()))
.thenReturn(responseEntity);
serviceClass.serviceMethod(businessObject);
verify(serviceClass, times(1)).serviceMethod(Mockito.any(BusinessClass.class));
}
}
简单来说,我将添加以下测试 class ,这确实足以满足您的情况。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ServiceClassTest {
private static final String CODE = "code";
private static final String NOTIFICATION_URL = "notificationUrl";
@Mock
private Config config;
@Mock
private RestTemplate restTemplate;
@InjectMocks
private ServiceClass serviceClass;
@Mock
private BusinessClass businessObject;
@Mock
private Notification notification;
@Test
public void serviceMethod() {
when(businessObject.getCode()).thenReturn(CODE);
when(config.getApplicationProperty(CODE)).thenReturn(notification);
when(notification.getNotificationUrl()).thenReturn(NOTIFICATION_URL);
serviceClass.serviceMethod(businessObject);
verify(restTemplate, times(1)).exchange(NOTIFICATION_URL, HttpMethod.POST, new HttpEntity<>(businessObject), String.class);
}
}
如果我简要说明此测试方法的作用
ServiceClass
中的代码。 所以在第 1 行:我确保businessObject.getCode()
返回我想要的CODE
。 请注意, businessObject
是我们要在测试方法中传递给ServiceClass.serviceMethod(BusinessClass businessObject)
的参数。 现在我知道,无论是哪种情况, businessObject.getCode()
都会返回CODE
,因此当我调用Config.getApplicationProperty(String code)
时,在我的ServiceClass.serviceMethod
(原始类)中, CODE
将作为参数传递。 现在在第 2 行:我建议每当CODE
作为config.getApplicationProperty(String code)
的参数传递时返回我想要的notification
。 在第 3 行:依次,我建议notification.getNotificationUrl()
返回NOTIFICATION_URL
。Mockito.verify
来确保执行与我的模拟安排和实际(原始)class 逻辑一致。 我在这里验证的是执行代码调用restTemplate
的方式。正如我在开头提到的,我上面写的是一个简单的测试来满足您的要求。 消化后,您可能会查看mock-server ,这可能有助于您执行 rest 调用的测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.