摘要:我有一个独立的类,用于执行代理登录,然后用浏览器可以使用的身份验证内容填充HttpServlet响应对象。在测试我的代码时,如何将模拟服务提供到一个没有setter的类中?
详细信息:我已经将我的代理登录代码严格地编辑到了这个片段中。
- 它向服务器请求登录表单
- 它会发回凭据
- 它获得服务器的批准并将其传递给浏览器(回应)
修剪后的代码如下所示:
private static final Log log = LogFactory.getLog(MyClass.class);
@Inject()
private UserService userService;
public void performProxyLogin(HttpServletResponse response,
UserDTO userDTO, String url) {
String username = getUsername(userDTO);
String password = getPasswordFromUserService(username);
// MyRequest only has data, organizing a Http Request.
MyRequest myRequest = prepareInitialGetRequest(url);
// processURLRequest() encapsulates use of HttpURLConnection.
// MyResponse only has data, organizing a Http Response.
MyResponse myResponse = processURLRequest(myRequest);
myRequest = prepareLoginRequest(myResponse, username, password);
myResponse = processURLRequest(myRequest);
// Transfer data into the response, and from there into the browser.
fillResponseWithProxiedResult(response, myResponse)
}
为了实现这一点,我认为我需要注入一个模拟日志或LogFactory,一个模拟UserService,以及一种获得模拟HttpURLConnection的方法。
然而,我看到的所有建议都涉及到带有setter的代码,测试套件可以使用setter来插入模拟对象。
如何为类提供所需的模拟对象?
咬紧牙关,为该字段提供一个包私有设置程序。
如果你想使用mock,那么让注入框架设置一个可以注入的mock是没有价值的,因为你在测试的设置中添加了更多的仪式和开销。
如果您想验证您是否有正确的服务注入,那么您根本不想使用mock(想想真实或伪真实组件的"集成测试")。
许多其他答案都暗示了这一点,但我要更明确地说,是的,依赖注入的天真实现可能会破坏封装。避免这种情况的关键是,调用代码不应该直接实例化依赖项(如果它不关心它们的话)。这可以通过多种方式实现。最简单的方法就是简单地使用一个默认构造函数来注入默认值。只要调用代码只使用默认构造函数,就可以在不影响调用代码的情况下更改后台的依赖关系。如果你的依赖项本身有依赖项等等,这可能会开始失控。这时,Factory模式就可以就位了(或者您可以从一开始就使用它,这样调用代码就已经在使用Factory了)。如果您引入了工厂,并且不想破坏代码的现有用户,那么您可以始终从默认构造函数调用工厂。除此之外,还有使用控制反转。我还没有充分使用IoC来谈论它,但这里有很多问题,还有网上的文章对它的解释比我所能解释的要好得多。如果它应该真正封装到调用代码无法知道依赖项的地方,那么如果语言支持,可以选择将注入(带有依赖项参数的构造函数或setter)设置为内部注入,或者将它们设置为私有注入,如果语言支持的话,可以让单元测试使用反射之类的东西。如果你的语言既不支持也不支持,那么我想一种可能性可能是让调用代码的类实例化一个伪类,这个伪类只是封装了类,并完成了真正的工作(我相信这是Facade模式,但我从来没有正确记住过名称)]