如何编写静态void方法的单元测试

时间:2020-10-27 15:59:47

标签: java unit-testing mockito httpclient junit5

我遇到了一个问题,我不知道如何编写静态void方法的单元测试。

我有一个使用Apache HttpClient的HttpHelper类。像下面的代码。

public class HttpHelper {
    private static CloseableHttpClient httpClient;

    public static void init() {
        httpClient = HttpClients.custom().setSSLContext(getDummySSL()).build();
    }

    public static void closeHttpClient() throws IOException {
        httpClient.close();
    }

    private static SSLContext getDummySSL() {
        ...omit
    }

    private static void send() {
        HttpGet httpGet = new HttpGet("https://someUrl.com");

        try(CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
            if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                responseString = EntityUtils.toString(httpResponse.getEntity());
                // do something
            } else {
                throw new Exception();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

因此在我的主目录中,我将调用HttpHelper.init()来初始化httpClient。每当我想发送请求时,我都会打给HttpHelper.send()。因为我不想每次都创建一个新的httpClient。最后,我将呼叫HttpHelper.close()关闭httpClient。

我想知道如何测试那些无效方法。我的概念是在测试中创建一个CloseableHttpClient,然后调用HttpHelper.init()创建实际的一个。然后比较我的期望值和实际值是相同的。我说的对吗?

由于变量和方法被声明为静态。编写单元测试有点困难。有很多帖子说,使方法静态化是一种不好的做法。但是,在我的示例中,我不知道如何避免将它们声明为静态并保持单个CloseableHttpClient实例。

谢谢!

2 个答案:

答案 0 :(得分:1)

单实例保证主要通过Singleton模式解决。单元测试的一个常见技巧是使构造函数具有可见性,您可以在其中放置参数以进行测试。该类最终看起来像这样。

public class HttpHelper {
    private static HttpHelper INSTANCE = new HttpHelper();

    public static HttpHelper getInstance() {
        return INSTANCE;
    }


    private CloseableHttpClient httpClient;

    private HttpHelper() {
        SSLContext sslContext = getDummySSL();
        this(HttpClients.custom().setSSLContext(sslContext).build(), sslContext);
    }

    protected HttpHelper(CloseableHttpClient httpClient, SSLContext sslContext) {
        this.httpClient = httpClient;
    }

    public void closeHttpClient() throws IOException {
        httpClient.close();
    }

    private static SSLContext getDummySSL() {
        ...
    }

    private void send() {
        ...
    }
}

我也将getDummySSL重命名为createDummySSL,但这很详细。

答案 1 :(得分:0)

拥有一个静态类是不好的,因为很难对此进行测试。我知道您为什么要这样做,但是您可能会得到所有相同的好处:

public class HttpHelper {

    private static HttpHelper DEFAULT_INSTANCE = null;

    private CloseableHttpClient httpClient;

    public HttpHelper(CloseableHttpClient httpClient) {
        this.httpClient = httpClient;
    }

    public static void getDeafultInstance() { // this should probably be synchronised for thread safety
        if (DEFAULT_INSTANCE == null) {
            DEFAULT_INSTANCE = httpClient = HttpClients.custom().setSSLContext(getDummySSL()).build();
        }
        return DEAFULT_INSTANCE;
    }

    private static SSLContext getDummySSL() {
        ...omit
    }

    public void closeHttpClient() throws IOException {
        httpClient.close();
    }

    private void send() {
        HttpGet httpGet = new HttpGet("https://someUrl.com");

        try(CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
            if(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                responseString = EntityUtils.toString(httpResponse.getEntity());
                // do something
            } else {
                throw new Exception();
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

然后您可以像这样对它进行单元测试:


public class HttpHelperTest {

    @Test
    public testSendsRequestToSomeUrl() {
        CloseableHttpClient httpClientMock = mock();
        when(httpClient.execute(any())).thenReturn(..http_response_where_stauts_code_is_ok..)
        HttpHelper httpHelper = new HttpHelper(httpClientMock)
        httpHelper.send()
        verify(httpClient).execute(new HttpGet("https://someUrl.com"))
    }

}

并在这样的实际代码中使用它:

HttpHelper.getDeafultInstance().send()

P.S。

如果您有某种类型的依赖注入框架,那么您完全可以摆脱静态方法。