首页 > 解决方案 > 为具有不带参数的方法的接口编写单元测试用例

问题描述

我有一个接口,它有一个没有参数的方法

public interface HealthStatus {
    Integer healthCheck();
}�

实现如下

 @Override
    public Integer healthCheck() {
        Integer status = 0;
        try {
            SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
            if (proxyConfigProperties.getEnabled()) {
                Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress(proxyConfigProperties.getUrl(), proxyConfigProperties.getPort()));
                simpleClientHttpRequestFactory.setProxy(proxy);
            }
            RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(simpleClientHttpRequestFactory));
            ResponseEntity<String> healthResponse = restTemplate.exchange(eVerifyGovernmentProperties.getUrl(), HttpMethod.GET, null, String.class);
            status = (healthResponse.getStatusCode() == HttpStatus.OK) ? 200 : 202;
        } catch (Throwable th) {
            th.printStackTrace();
        }

        return status;
    }�

我如何针对正面场景和负面场景对该方法进行单元测试。

编辑:

我已经重构了我的类如下

@Service
@Qualifier("implementation")
public class HealthStatusImpl implements HealthStatus {

    @Autowired
    RestTemplateConfig restTemplateConfig;

    @Autowired
    private EVerifyGovernmentProperties eVerifyGovernmentProperties;

    @Override
    public Integer healthCheck() {
        Integer status = 0;
        try {
            ResponseEntity<String> healthResponse = restTemplateConfig.getRestTemplate().exchange(eVerifyGovernmentProperties.getUrl(), HttpMethod.GET, null, String.class);
            status = (healthResponse.getStatusCode() == HttpStatus.OK) ? 200 : 202;
        } catch (Throwable th) {
            th.printStackTrace();
        }

        return status;
    }

}

这是实例化 RestTemplate 的类

@Component
public class RestTemplateConfig {

    @Autowired
    ProxyConfigProperties proxyConfigProperties;

    public RestTemplate getRestTemplate(){
        SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
        if (proxyConfigProperties.getEnabled()) {
            Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress(proxyConfigProperties.getUrl(), proxyConfigProperties.getPort()));
            simpleClientHttpRequestFactory.setProxy(proxy);
        }
        RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(simpleClientHttpRequestFactory));
        return restTemplate;
    }
}

标签: javajunitinterface

解决方案


实际上,这就是您要模拟的内容:

restTemplateConfig.getRestTemplate().exchange(eVerifyGovernmentProperties.getUrl(), HttpMethod.GET, null, String.class);

但这将需要深度模拟,这也是一种不好的气味:您不需要定义这样的语句来调用其余模板。这个责任应该在一个特定的类中定义。
因此,例如,将它移动到特定 bean 的方法中,RestTemplateService这将使您免于传递尽可能多的参数,并且还可以通过减少其依赖关系来平衡该类的更好责任:

ResponseEntity<String> healthResponse =  restTemplateService.getForHealthCheck();

现在只需用 Mockito 模拟它。
关于RestTemplateService,您可以创建自己的类或依赖 Feign(这里Spring Feign更有意义)通过接口启用声明式休息客户端。

它会给:

public class HealthStatusImpl implements HealthStatus {

    private RestTemplateService restTemplateService;

    // favor constructor injection
    public HealthStatusImpl(RestTemplateService restTemplateService){
        this.restTemplateService = restTemplateService;
    }

    @Override
    public Integer healthCheck() {
        Integer status = 0;
        try {
            ResponseEntity<String> healthResponse = restTemplateService.getForHealthCheck();
            status = healthResponse.getStatusCode().is2xxSuccessful() ? 200 : 400;
        } catch (Throwable th) {
            th.printStackTrace();
        }

        return status;
    }
}

请注意,这 Status.is2xxSuccessful()通常会更好,因为它对任何成功的响应( 、 等)都返回200true 201。如果它不成功,你想返回一个错误响应代码。

在单元测试方面,您应该模拟此依赖项并根据您的场景记录模拟行为。
请注意,在您的情况下,您不想加载整个 spring 上下文,但您想执行一个普通的单元测试,即没有容器。所以不要@SpringBootTest只使用 JUnit 和 Mockito。

例如 JUnit 5 :

@ExtendWith(MockitoExtension.class)
public class HealthStatusImplTest{

    private HealthStatusImpl healthStatusImpl;

    @Mock
    private RestTemplateService restTemplateServiceMock;

    @BeforeEach
    public void beforeEach(){
        healthStatusImpl = new HealthStatusImpl(restTemplateService);
    }

    @Test
    public void healthCheck_when_200_is_returned(){
       Mockito.when(restTemplateServiceMock)
              .getForHealthCheck().thenReturn(new ResponseEntity(HttpStatus.OK));
       assertEquals(200, healthStatusImpl.healthCheck());
    }

    @Test
    public void healthCheck_when_200_is_not_returned(){
       Mockito.when(restTemplateServiceMock)
              .getForHealthCheck().thenReturn(new ResponseEntity(HttpStatus.NOT_FOUND));
       assertEquals(400, healthStatusImpl.healthCheck());
    }

}

当然,RestTemplateService也应该是单一测试,而单一测试并不能减轻为更高级别组件编写集成测试的负担。


推荐阅读