繁体   English   中英

单元测试或模拟:使用 Rest 模板启动 Spring 中的测试服务 Class

[英]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);
    }
}

如果我简要说明此测试方法的作用

  • 前 3 行:做必要的 mocking 以确保我们的测试方法只依赖于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
  • 调用我们要测试的方法。 注意我们不应该是mocking这个方法。
  • 由于这是一个 void 方法,我使用Mockito.verify来确保执行与我的模拟安排和实际(原始)class 逻辑一致。 我在这里验证的是执行代码调用restTemplate的方式。

正如我在开头提到的,我上面写的是一个简单的测试来满足您的要求。 消化后,您可能会查看mock-server ,这可能有助于您执行 rest 调用的测试。

暂无
暂无

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

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