我正在尝试设置单元测试。我正在使用Struts2和Liferay 6.1。
我收到以下错误
java.lang.NullPointerException
at com.liferay.portal.util.PortalUtil.getCompany(PortalUtil.java:305)
at com.mycomp.portlet.action.BasePortletAction.setupSiteAgent(BasePortletAction.java:1169)
这是因为PortalUtil.getPortal()
返回null
。有没有办法我可以以某种方式创建一个模拟门户网站?没有MockPortal
类。我发现了一些名为MockPortalContext
的东西,但我不确定如何使用它。
这是我目前的代码
BaseTestCase.java
public abstract class BaseTestCase extends TestCase {
private Dispatcher dispatcher;
protected ActionProxy proxy;
private static MockServletContext servletContext;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
public BaseTestCase(String name) {
super(name);
}
@SuppressWarnings("unchecked")
protected <T>T createAction(Class<T> theClass, String namespace, String actionName, String methodName, HashMap<String, Object> actionContextMap, HashMap<String, Object> parameterMap) throws Exception {
proxy = dispatcher.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, actionName, methodName, new HashMap<String, Object>(), true, true);
for (String key : actionContextMap.keySet()) {
proxy.getInvocation().getInvocationContext().put(key, actionContextMap.get(key));
}
proxy.getInvocation().getInvocationContext().setParameters(parameterMap);
proxy.setExecuteResult(true);
ServletActionContext.setContext(proxy.getInvocation().getInvocationContext());
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
ServletActionContext.setRequest(request);
ServletActionContext.setResponse(response);
ServletActionContext.setServletContext(servletContext);
return (T) proxy.getAction();
}
protected void setUp() throws Exception {
final String[] config = new String[]{"struts.xml", "mockApplicationContext.xml"};
servletContext = new MockServletContext();
final XmlWebApplicationContext appContext = new XmlWebApplicationContext();
appContext.setServletContext(servletContext);
appContext.setConfigLocations(config);
appContext.refresh();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, appContext);
HashMap<String, String> params = new HashMap<String, String>();
params.put("actionPackages", "com.mycomp.portlet.action");
dispatcher = new Dispatcher(servletContext, params);
dispatcher.init();
Dispatcher.setInstance(dispatcher);
}
}
ActionTest.java
public class ActionTest extends BaseTestCase {
private Map<String, Object> contextMap;
private Map<String, Object> parameterMap;
private MockPortletRequest portletRequest;
private final String REQUEST_LOCALE = "request_locale";
public ActionTest(String name) {
super(name);
}
public void testShowDetail() throws Exception {
init();
parameterMap = new HashMap<String, Object>();
parameterMap.put(REQUEST_LOCALE, "en_GB");
@SuppressWarnings("unused")
PortletAction lspa = createAction(PortletAction.class,
"/view",
"myAction",
"myAction",
(HashMap<String, Object>)contextMap,
(HashMap<String, Object>)parameterMap);
String result = proxy.execute();
System.out.println(result);
}
private void init() {
portletRequest = new MockPortletRequest();
contextMap = new HashMap<String, Object>();
contextMap.put(PortletActionConstants.REQUEST, portletRequest);
}
}
Spring documentation说使用no-arg构造函数创建MockPortletRequst()
会使用默认MockPortletContext
和MockPortalContext
创建它,所以我不知道为什么它为null。< / p>
答案 0 :(得分:1)
使用Powermock或jMockit模拟静态方法调用PortalUtil.getPortal()
答案 1 :(得分:0)
从技术上讲,John B.已经给出了答案。我想补充一个哲学角度。
嘲笑像门户网站这样的复杂环境的恕我直言并不买很多,尤其是当我们谈论单元测试时。通过最大限度地减少与任何复杂API和环境(不仅仅是门户网站)的联系,您可以更深入地了解您的代码,而不是与API分离。一种解决方案是在portlet类中进行非常简单的连接(并对代码进行查看),同时将可测试代码提取到自己的 - 经过充分测试的类中,这些类不会调用外部API,而是将其上下文传递给
这将为您提供一些非经过单元测试的非常简单的代码,但除了代码审查之外,您还可以(并且应该)添加一些实际在整个环境中工作的集成/冒烟测试。
有时一个简单的解决方案是快速模拟门户类(或其他外部类),但我不认为这是首选解决方案。一旦您开始编写重要的设置代码来准备环境,您的测试运行时就没有任何收获。如果它失败了,你将不得不在真实环境中检查它,看看你的设置是否准确。
对不起,如果这是个坏消息 - 恕我直言,当你有任何给定的API没有在单元测试中可更换时,它是固有的。而且我不愿意在单元测试中经常进行大型设置程序。如果经常发生这种情况,我不会称它们为单元测试 - 而是将(过于复杂的)单元分解为更小的单元。或者接受两个不同API之间的简单布线(适配)代码的代码审查。