背景
我正在开发一个 Java 应用程序套件,通过 HTTP post/get 调用不同的子系统。在我对所有内容进行单元测试的过程中,我遇到了无法使用 Mockito 的问题。直接模拟,因为 URL
类是 final
。
我在哪里
由于 URL
类无法被模拟,因此我决定创建一个包装类,并且仅公开我正在使用的 URL
类的方法。您可以在下面找到该类(class)。这似乎工作得很好,直到我开始尝试在测试上下文中设置我的 bean。
UrlWrapper
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class UrlWrapper {
URL url;
public UrlWrapper(String spec) throws MalformedURLException{
url = new URL(spec);
}
public URLConnection openConnection() throws IOException{
return url.openConnection();
}
}
单元测试方法
@Test
public final void testToMockConstructorInjectedBean()
throws IOException {
GenericApplicationContext mockContext = new GenericApplicationContext();
// Create our mock controller
UrlWrapper mockUrl = mock(UrlWrapper.class);
// Set the mock object in the context
mockContext.refresh();
mockContext.getBeanFactory().registerSingleton("url", mockUrl);
UrlWrapper mock = null;
mock = (UrlWrapper)mockContext.getBean("url"); // <-- Works
mock = (UrlWrapper)mockContext.getBean("url", "http://google.com/"); // <-- Fails.
}
问题
我真正喜欢的是弄清楚如何让单元测试中“失败”的行正常工作。这对其余代码的影响最小,并且是理想的。我可以采取的另一个选择是修改我的包装器,使其具有接受 String
并在内部创建一个新的 URL
对象的 set 方法,但对我来说感觉像是代码味道。使用 URL 进行单元测试代码的“正常”正确方法是什么?另外,如何模拟在注入(inject)期间接受构造函数参数的单元测试上下文?
编辑 1
上下文提供者
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ContextProvider {
private static ApplicationContext appContext;
public static void setContext(ApplicationContext context) {
appContext = context;
}
public static ApplicationContext getContext() {
if (appContext == null) {
appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
}
return appContext;
}
}
单元测试之外的示例用法
public boolean post() throws IOException {
UrlWrapper url;
// Get my URL from the available context (either 'live' or 'test' context)
url = (UrlWrapper) ContextProvider.getContext().getBean("url", requestUrl);
/* More code here omitted for brevity */
}
最佳答案
对于您的情况,我建议您看一下 Mockito 的 Spy
。 Here是 javadoc 和 here是它的使用教程。
在您的情况下,您将创建真实 URLWrapper 对象的 spy ,然后执行所需的任何其他交互。
@Test
public final void testToMockConstructorInjectedBean()
throws IOException {
GenericApplicationContext mockContext = new GenericApplicationContext();
// Create our mock controller
UrlWrapper spyUrl = spy(new URLWrapper("http://google.com"));
// Set the mock object in the context
mockContext.refresh();
mockContext.getBeanFactory().registerSingleton("url", spyUrl);
UrlWrapper spy = null;
spy = (UrlWrapper)mockContext.getBean("url");
}
在本例中,您使用指定的 URL 创建 spy ,然后将该对象注册为该类的 bean。
更新
我认为
url = (UrlWrapper) ContextProvider.getContext().getBean("url", requestUrl);
在测试代码中是限制性的。像这样的代码意味着需要以特定方式(静态工厂方法)创建 bean,以便能够按照测试的预期进行创建。我建议您使用已包含所需行为的 bean 填充 Spring 上下文,然后仅使用不带参数的 getBean
关于java - 我如何模拟 java.net.URL 或以编程方式设置 spring bean 来接受构造函数参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25308524/