为具有无参数方法的接口编写单元测试用例

时间:2019-06-23 07:50:47

标签: java junit interface

我有一个接口,该接口的方法不带参数

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;
    }
}

3 个答案:

答案 0 :(得分:1)

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

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

但是这将需要深入的模拟,这也是一种难闻的气味:您无需定义这样的语句即可调用其余模板。此责任应在特定的类别中定义。
因此,将其移至特定的bean方法(例如RestTemplateService)中,这将使您避免传递尽可能多的参数,并且还将通过减少其依赖关系来平衡此类的更好职责:

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

现在只需使用Mockito对其进行模拟。
关于RestTemplateService,您可以创建自己的类,也可以依赖Feign(在这里Spring Feign更有意义)来通过接口启用声明式rest客户。

它将给出:

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()通常更好,因为对于任何成功的响应(200201等),它都返回true。如果不成功,则要返回错误响应代码。

从单元测试方面,您应该模拟此依赖关系,并根据您的方案记录模拟行为。
请注意,在您的情况下,您不想加载整个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也应该是单一测试,并且单一测试不能免除编写针对更高级别组件的集成测试的麻烦。

答案 1 :(得分:0)

要对Web客户端(例如基于RestTemplate的类)进行单元测试,您需要一个模拟服务器的框架,例如

答案 2 :(得分:0)

我不确定您的支票Text('You have no messages')是否正确,因为如果状态不是(healthResponse.getStatusCode() == HttpStatus.OK)2xx会抛出RestTemplate

这就是为什么如果您与第三方集成在一起,总是有一些模拟效果会更好。

这就是为什么我还建议您在测试中考虑HttpStatusCodeException的原因。请参阅@Puce答案以获取链接。

此外,也不必为每个请求创建一个新的MockRestServiceServer

这就是为什么我也建议您考虑构造函数注入的原因。有关重构方法,请参见@davidxxx答案。并且不要忘记在您的RestTemplate设置中添加连接超时。