我想为servlet类编写单元测试,该类通过java.net.URL调用Web服务。
我可以创建模拟请求和响应对象,以便轻松地发送到servlet的doGet方法(使用junit上的实用程序员文本中的技术),即创建MockHttpServletRequest,MockHttpServletResponse,并将这些传递给doGet。
我遇到问题的部分是在servlet中打开的URL。
现在,我只是在调用打开URL的函数并返回一个字符串(生产代码)和调用返回的函数之间进行选择,该函数直接返回一个固定URL的字符串(测试代码)
理想情况下,我想要一个doGet方法,其中测试代码是不可见的 - 在进行网络访问的函数和直接返回字符串的函数之间的选择应该对doGet是透明的。
我可以想到实现这一目标的多种方法,但没有一种感觉正确。
示例1:将函数包装在具有testOn布尔值和setTestMode方法的类中; junit init可以将testMode设置为true,默认为false。 testOn决定调用哪个方法。否定的是,我需要一个新的课程,似乎可能会失控。
示例2:有两个实现网络访问的类,其中一个是mock;让junit重新加载mock类,生成代码加载常规类(或以某种方式将生产类重新映射到mock类)。否定:不确定如何做到这一点;看起来很笨拙。
示例3:有一个带有静态字段的类,指示我是否要使用模拟,并根据字段值调整servlet中的URL访问。否定:感觉就像全局变量。
示例4:扩展URL,如果我只切换到URL(但java.net.URL是最终的),生产代码将正常工作。
通过上午的搜索,我找不到合适的答案,因此我转向了SO的集体智慧。
谢谢, 阿德南
ps - 我应该提一下,我不必使用java.net.URL,任何相同的东西都可以工作。
答案 0 :(得分:3)
您的第二个选项是“正确”选项。对外部URL的调用应该封装在服务中。然后,该服务被注入使用它的servlet中。这是Inversion of Control派上用场的地方。
在您的单元测试中,您将注入测试实现,在现实生活中,您将注入一个真正的实现。它可以像为服务提供setter一样简单,并将实现默认为“真正的”。
这种事情是IoC / DI的典型例子。
答案 1 :(得分:2)
看起来你正在重新发明轮子 - 你又在示例2 中发明了它。这通常使用依赖注入来实现,实际上是迄今为止软件开发人员提出的最佳解决方案。
隐藏界面后面的Web服务调用。一个实现执行实际调用,而另一个实现是可以配置的模拟。如果您没有使用任何DI框架(Spring,Guice,EJB / CDI),请在测试中手动替换生产实现。