java - 如何使用单例类实现依赖注入(inject)

标签 java junit dependency-injection

我正在尝试学习用 Java 编写可测试的代码。我看到很多链接说如果我想做单元测试,单例类不太好实现。这就是我想要解决的问题。我有一个发送 HTTP 请求的类(HTTPRequest 类)。我希望这个类担心使用哪个协议(protocol)(TLSv1.2 等)。我有多个其他类,它们仅使用正文、URL 等调用 HTTPRequest 类。

我的方法是 HTTPRequest 可以是一个单例类,因为不需要创建同一事物的多个实例。整个项目的协议(protocol)将是相同的,并且只需要设置一次。

这就是我的 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,但只使用一个对象吗?我读过一些有关依赖注入(inject)的内容,但我真的不知道应该如何做。

我应该如何修改代码以使其也可测试?

最佳答案

你可以做的就是删除 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);
    }

    ...
}

最后,可以注入(inject)HttpRequestHttpRequestMock相应地在您的单元测试中。

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
        ...
      }

关于java - 如何使用单例类实现依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41625811/

相关文章:

java - JUnit 测试不使用 SpringJUnit4ClassRunner 回滚

c# - 使用带有 CaSTLe 代理拦截器的简单注入(inject)器

java - 具有多个参数的方法的 Autowiring spring 注释

c# - 如何为 C# Azure Function 编写单元测试?

java - 如何反转短语中单词的顺序并反转单词中的字母?

java - 从 Intellij 编译项目时在 Maven 项目上获取 "no groovy library is defined for module"

java - 如何在spring boot中测试文件上传?

java - 如何从Java中的主类访问src.test包或如何从主类运行测试类?

java - 删除 createButtonsForButtonBar 或使其有用 - JFace Dialogs

java - Hibernate 多对一外键默认值 0