如何编写静态无效方法的单元测试
How to write unit test of a static void method
我遇到了一个问题,我不知道如何编写 static void 方法的单元测试。
我现在有一个使用 Apache HttpClient 的 HttpHelper class。代码如下。
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。
我想知道如何测试那些 void 方法。我的想法是在我的测试中创建一个 CloseableHttpClient
,然后调用 HttpHelper.init()
来创建实际的。然后比较我预期的和实际的是一样的。我说得对吗?
由于变量和方法被声明为静态的。编写单元测试有点困难。有很多帖子说使方法静态化是一种不好的做法。但是在我的示例中,我不知道如何避免将它们声明为静态并保留单个 CloseableHttpClient
实例。
谢谢!
单实例保证主要是用单例模式解决的。单元测试的一个常见技巧是创建一个具有受保护可见性的构造函数,您可以在其中放置参数进行测试。 class 终于可以变成这个样子了。
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
但这是细节。
class 如此静态是不好的,因为很难对其进行测试。我理解您为什么想要这个,但您可以获得与此相同的所有好处:
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.
如果你有某种可用的依赖注入框架,那么你完全可以摆脱静态方法。
我遇到了一个问题,我不知道如何编写 static void 方法的单元测试。
我现在有一个使用 Apache HttpClient 的 HttpHelper class。代码如下。
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。
我想知道如何测试那些 void 方法。我的想法是在我的测试中创建一个 CloseableHttpClient
,然后调用 HttpHelper.init()
来创建实际的。然后比较我预期的和实际的是一样的。我说得对吗?
由于变量和方法被声明为静态的。编写单元测试有点困难。有很多帖子说使方法静态化是一种不好的做法。但是在我的示例中,我不知道如何避免将它们声明为静态并保留单个 CloseableHttpClient
实例。
谢谢!
单实例保证主要是用单例模式解决的。单元测试的一个常见技巧是创建一个具有受保护可见性的构造函数,您可以在其中放置参数进行测试。 class 终于可以变成这个样子了。
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
但这是细节。
class 如此静态是不好的,因为很难对其进行测试。我理解您为什么想要这个,但您可以获得与此相同的所有好处:
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.
如果你有某种可用的依赖注入框架,那么你完全可以摆脱静态方法。