我正在努力学习用Java编写Testable代码。我已经看到很多链接说如果我想进行单元测试,单例类的实现并不好。所以这就是我想要解决的问题。我有一个发送HTTP请求(HTTPRequest类)的类。我希望这个类担心使用哪个协议(TLSv1.2等)。我有多个其他类只调用带有body,URL等的HTTPRequest类。
我接近它的方式是HTTPRequest可以是单例类,因为不需要创建同一事物的多个实例。整个项目的协议将是相同的,只需要设置一次。
这就是我的HTTPRequest的样子。
public class HTTPRequest {
private CloseableHttpClient httpClient;
private HttpGet httpGet;
private HttpPut httpPut;
private HttpPost httpPost;
HTTPRequest(CloseableHttpClient a, HttpGet b, HttpPut c, HttpPost d) {
httpClient = a;
httpGet = b;
httpPut = c;
httpPost = d;
}
public HTTPResponse getRequest(url) {
//Do some processing with httpClient & httpGet to send the request
}
}
现在从需要HTTPRequest的类中有一种方法可以调用getRequest,但只使用一个对象吗?我读了一些关于依赖注入的内容,但我真的无法弄清楚应该怎么做。
我应该如何修改代码以使其可以测试?
答案 0 :(得分:1)
您可以做的是删除HTTPRequest
课程中的构造函数,然后创建名为protected
,getHttpGet()
等的getHttpPut
方法。
public class HTTPRequest {
public HTTPResponse getRequest(url) {
//Do some processing with httpClient & httpGet to send the request
getHttpGet(url).call();
}
protected CloseableHttpClient getHttpClient() {
return new CloseableHttpClient();
}
protected HttpGet getHttpGet(String url) {
return new HttpGet(url);
}
protected HttpPost getHttpPost(String url) {
return new HttpPost(url);
}
...
}
然后,您可以创建一个继承自HttpRequestMock
并覆盖HttpRequest
方法的getHttp*
类。
public class HTTPRequestMock extends HttpRequest {
@Override
protected CloseableHttpClient getHttpClient() {
//return mock
return new CloseableHttpClientMock();
}
@Override
protected HttpGet getHttpGet(String url) {
//return mock
return new HttpGetMock(url);
}
@Override
protected HttpPost getHttpPost(String url) {
//return mock
return new HttpPostMock(url);
}
...
}
最后,您可以在单元测试中相应地注入HttpRequest
或HttpRequestMock
。
class HTTPRequestClient {
private HTTPRequest httpRequest = HttpRequestFactory.getHttpRequest();
public void callServer(){
httpRequest.getRequest("http://someurl.com/");
}
void setHttpRequest(HTTPRequest httpRequest){
this.httpRequest = httpRequest;
}
}
class HTTPRequestFactory {
private static final HttpRequest httpRequest = new HttpRequest();
public static HTTPRequest getHttpRequest() {
return httpRequest;
}
}
class HTTPRequestClientTest {
HTTPRequestClient httpRequestClient;
@Before
public void setUp(){
httpRequestClient = new HTTPRequestClient();
httpRequestClient.setHttpRequest(new HttpRequestMock());
}
@Test
...
}
答案 1 :(得分:0)
依赖注入(没有注入框架)的简单实现可以使用setter :
class SomeOtherClass {
private HTTPRequest httpRequest;
public void setHttpRequest(HTTPRequest httpRequest){
}
public void someAction(){
httpRequest.getRequest(...);
}
}
...
SomeOtherClass someOtherClass = new SomeOtherClass(httpRequest);
在上面的示例中,HttpRequest
(依赖项)被注入SomeOtherClass
。通过这种方式,单元测试可以创建HttpRequest
的模拟,将其提供给SomeOtherClass
并测试SomeOtherClass
,而不需要外部依赖项。
这有意义吗?
现在,关于单身人士:让HttpRequest成为单身人士会让 Mock 变得更难(使用像Mockito这样的模拟框架)。另外,像SomeOtherClass这样的类只能执行HttpRequest.getInstance(),所以你的测试无法做任何事情。
答案 2 :(得分:0)
beans.xml
的空文件放入WEB-INF
目录。 HttpRequest
。@ApplicationScoped
课程添加注释
@Inject
注释它们。