Java 如何使用singleton类实现依赖注入
我正在努力学习用Java编写可测试代码。我看到很多链接说,如果我想进行单元测试,单例类不适合实现。这就是我想要解决的问题。我有一个发送HTTP请求的类(HTTPRequest类)。我想让这个类考虑使用哪个协议(TLSv1.2等)。我有多个其他类,它们只是用body、URL等调用HTTPRequest类 我的方法是HTTPRequest可以是一个单例类,因为不需要创建同一事物的多个实例。整个项目的协议将是相同的,只需设置一次 这就是我的HTTPRequest的样子Java 如何使用singleton类实现依赖注入,java,junit,dependency-injection,Java,Junit,Dependency Injection,我正在努力学习用Java编写可测试代码。我看到很多链接说,如果我想进行单元测试,单例类不适合实现。这就是我想要解决的问题。我有一个发送HTTP请求的类(HTTPRequest类)。我想让这个类考虑使用哪个协议(TLSv1.2等)。我有多个其他类,它们只是用body、URL等调用HTTPRequest类 我的方法是HTTPRequest可以是一个单例类,因为不需要创建同一事物的多个实例。整个项目的协议将是相同的,只需设置一次 这就是我的HTTPRequest的样子 public class HTT
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,但只使用一个对象?我读了一些关于依赖注入的书,但我真的不知道该怎么做
我应该如何修改代码以使其也可测试?可以使用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
,而无需外部依赖项
这有意义吗
现在,关于singleton:使HttpRequest成为singleton会使模拟变得更加困难(使用类似Mockito的模拟框架)。另外,像其他类一样的类只能执行HttpRequest.getInstance(),所以您的测试对此无能为力。
- 将名为
的空文件放入beans.xml
目录李>WEB-INF
- 用
注释您的@ApplicationScoped
类HttpRequest
- 将本地字段添加到使用它的所有类中,并用
注释它们@Inject
HTTPRequest
类中删除构造函数,然后创建受保护的方法,称为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);
}
...
}
然后,您可以创建一个继承自HttpRequest
的HttpRequestMock
类,并重写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
...
}
是的,我想过这个。但是我不希望创建HttpRequest的责任由调用其他类的人来完成。在这种情况下我该如何处理呢?然后,您可以使用Spring或Guice之类的注入框架。该框架将实例化这些对象并将它们注入到您的bean中。那么在这种情况下,绑定应该在哪里进行呢?其他类将进行绑定吗?你能举个例子吗?老实说,注入框架一开始不是一个容易理解的概念,我觉得你最好先看一下教程。看看StackOverflow的文档:它显示了一个简单的工作解决方案。为什么要将HttpGet
、HttpPut
等作为构造函数中的参数传递?@alayor我想模拟HttpGet的响应。因为我不希望它实际上是我的服务器。但是你能在getRequest
方法中传递HttpGet
吗?@alayor是的,我可以。谢谢你的详细解释。然而,我将有多个HTTPRequestClients做各种各样的事情。我认为没有必要为每个类创建多个HTTPRequest对象。您可以创建一个HTTPRequestFactory
。而且您只能控制一个HTTPRequest
对象的创建。这很有意义。我会试试看。谢谢你的帮助:)