简体   繁体   English

使用方法内部的静态调用设计Java单元测试

[英]Designing Java unit test with static calls inside method

I'm trying to create a unit test for a class that has a method that uses Request.Post method from apache's fluent-hc library ( http://hc.apache.org/httpcomponents-client-ga/fluent-hc/apidocs/org/apache/http/client/fluent/Request.html ). 我正在尝试为一个类创建单元测试,该类的方法使用apache的fluent-hc库中的Request.Post方法( http://hc.apache.org/httpcomponents-client-ga/fluent-hc/apidocs /org/apache/http/client/fluent/Request.html )。

The thing is I don't want it to send an actual request every time I run the test suit, even less if its a unit test, not an integration one. 问题是我不希望每次运行测试服时都发送实际的请求,即使是单元测试而不是集成测试也是如此。 But I don't know how to make my way around that. 但是我不知道该如何解决。

I'm new in the testing world and for what I've read most of the time when you can't test something, there's a problem with the design of the class. 我是测试领域的新手,对于大多数时间我无法阅读的内容,该类的设计存在问题。

public class HttpRequestSenderServiceImpl implements RequestSenderService {

@Override
public Response sendRequest(String address, String messageBody) throws IOException {
    Request request = Request.Post(address).bodyString(messageBody, ContentType.APPLICATION_JSON);
    Response response = request.execute();

    return response;
}

} }

I'm using Spring framework and Spring-Test, Mockito and TestNG as testing tools. 我正在使用Spring框架和Spring-Test,Mockito和TestNG作为测试工具。 I'll really appreciate if you could at least point me in the right direction, any material to read, book, video, anything. 如果您至少能指出正确的方向,阅读的任何材料,书籍,视频或其他任何内容,我将不胜感激。 I just want to learn to do it the right way. 我只想学习正确的方法。

I've found some "solutions" to my problem but they all uses PowerMockito, and for what I've read is bad for you because allows mocking static methods, constructors, etc, which translate to bad coding practices, which is what I'm trying to avoid here. 我找到了解决问题的“解决方案”,但是它们都使用PowerMockito,因为我阅读的内容对您不利,因为允许模拟静态方法,构造函数等,这会转化为不良的编码做法,这就是我的意思。我试图避免在这里。

For your purpose the problem is more in the apache's fluent-hc Request.Post , that is static and not mock friendly, than in your code. 为了您的目的,问题更多是在Apache的fluent-hc Request.Post ,而不是代码友好,它是静态的,不是模拟友好的。

You can use Executor and mock execute method, or if you want to use Request.Post wrap it in another low level service interface and use it: 您可以使用Executor和模拟执行方法,也可以使用Request.Post将其包装在另一个低层服务接口中并使用它:

interface RequestSender {
      Response send(String addr,msgBody)
}

class RequestSenderImpl implements RequestSender {
    public Response send(String addr,msgBody) {
       Request request = Request.Post(address).bodyString(messageBody,ContentType.APPLICATION_JSON);
       Response response = request.execute();
       return response;
    }
}

That way you can easily mock the code even without mockito. 这样一来,即使没有模拟,您也可以轻松模拟代码。

@lujop has provided a suggestion for the problem mentioned which I believe is one way to do it. @lujop针对上述问题提供了建议,我认为这是解决问题的一种方法。

However, as to earlier statement of using mocking frameworks, I don't it is entirely a bad practice all the time. 但是,对于之前使用模拟框架的声明,我不是一直都是完全不好的做法。 Consider the suggestion from @lujop , you would probably end up using a Test Double to unit-test RequestSenderImpl and it's business logic. 考虑@lujop的建议,您可能最终会使用Test Double来对RequestSenderImpl及其业务逻辑进行单元测试。

But there would be a class, say - FluentHCRequestSender - which would be responsible for actually making a call to Request.Post . 但是会有一个类,例如FluentHCRequestSender ,它将负责实际调用Request.Post Now if you were writing UTs for all your classes, you would have to use mocking framework to test FluentHCRequestSender to ensure that this class is using the right API. 现在,如果您要为所有类编写UT,则必须使用FluentHCRequestSender框架来测试FluentHCRequestSender以确保该类使用了正确的API。

There is a place for tests using mocking frameworks. 有一个使用模拟框架进行测试的地方。 But generally, it justs points to a bad design if you end up using mocking frameworks if your dependencies are classes that you, your team or your organization has created. 但是总的来说,如果依赖项是您,您的团队或组织创建的类,而最终使用了模拟框架,那就说明设计不好。

And to answer your question of resources that can help you in writing better UT and code in general, 为了回答您的资源问题,这些资源通常可以帮助您编写更好的UT和代码,

SOLID principles - This is probably one thing that is always in the back of my mind while writing code. SOLID原则 -在编写代码时,这可能永远是我的脑海。

Working Effectively with Legacy Code which has served me well. 有效地使用旧版代码对我很有帮助。

Test Driven Development - During my practice, not very easy to strictly follow in your day-to-day routine, but it at least forces me not to put-off my UTs and work on them simultaneously with my actual classes (if not before). 测试驱动的开发 -在我的练习中,要严格遵循日常工作并非易事,但这至少迫使我不要推迟UT并与我的实际课程同时进行(如果不是之前) 。

Design Patterns - Grab hold of a good design pattern book/video if a library is accessible to you or buy one. 设计模式 -如果您可以访问或购买图书馆,则可以抓住一本好的设计模式书/视频。 The concepts might seem intimidating, but I find some of them really useful in my day-to-day work and especially while writing UTs. 这些概念看似令人生畏,但我发现其中一些确实对我的日常工作特别是在编写UT时有用。

But personally, the best way to learn to see existing code in your code base and see what's good and what can be improved. 但就个人而言,这是学习在代码库中查看现有代码并了解有什么好处和可以改进的最好方法。 I have found looking and understanding code written by people who do good design much more useful than any of the books. 我发现寻找和理解由擅长设计的人编写的代码比任何书籍都有用。

Hope this long winding post helps !! 希望这篇冗长的帖子对您​​有所帮助!

PS - Kudos on trying to do the right way. PS-尝试正确方法的荣誉。 Sometimes it is not said often, although it should be. 有时它不是应该经常说,尽管应该这样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM