我遇到了一个问题,我不知道如何编写静态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
实例。
谢谢!
答案 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。
如果您有某种类型的依赖注入框架,那么您完全可以摆脱静态方法。