有没有办法模拟 Portal?
Is there a way to mock a Portal?
我正在尝试设置单元测试。我正在使用 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()
returnsnull
。有什么办法可以创建一个模拟门户吗?没有MockPortal
class。我找到了一个叫做 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 说使用无参数构造函数创建 MockPortletRequst()
会使用默认的 MockPortletContext
和 MockPortalContext
创建它,所以我不知道为什么它为空.
使用Powermock或jMockit模拟静态方法调用PortalUtil.getPortal()
技术上答案已经由 John B 给出。我想补充一个哲学角度。
恕我直言,模拟像门户这样的复杂环境并没有多大意义,尤其是当我们谈论 单元 测试时。通过尽量减少与 any 复杂 API 和环境(不仅仅是门户)的接触,而不是与 API 分离,您将更深入地了解您的代码。
一个解决方案是在 portlet 类 中进行非常简单的连接(并对此进行代码审查),同时将可测试代码提取到它自己的代码中 - 经过全面测试 - 类 不会调用外部 API,而是让他们的上下文传入。
这会给您留下一些未经单元测试的非常简单的代码,但除了代码审查之外,您还可以(并且应该)添加一些 integration/smoke 在完整环境中实际工作的测试。
有时一个简单的解决方案是快速模拟门户 类(或其他外部 类),但我不认为这是首选解决方案。一旦您开始编写重要的设置代码来准备环境,您在测试运行时将一无所获。如果它失败了,无论如何你都必须在真实环境中检查它,看看你的设置是否准确。
抱歉,如果这是个坏消息 - 恕我直言,当您有任何给定的 API 尚未构建且无法在单元测试中替换时,这是固有的。而且我不愿意在 unit 测试中例行进行大型设置例程。如果这种情况经常发生,我不会称它们为单元测试——而是将(太复杂的)单元分解成更小的单元。或者接受两个不同 APIs.
之间的简单接线(适配)代码的代码审查
我正在尝试设置单元测试。我正在使用 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()
returnsnull
。有什么办法可以创建一个模拟门户吗?没有MockPortal
class。我找到了一个叫做 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 说使用无参数构造函数创建 MockPortletRequst()
会使用默认的 MockPortletContext
和 MockPortalContext
创建它,所以我不知道为什么它为空.
使用Powermock或jMockit模拟静态方法调用PortalUtil.getPortal()
技术上答案已经由 John B 给出。我想补充一个哲学角度。
恕我直言,模拟像门户这样的复杂环境并没有多大意义,尤其是当我们谈论 单元 测试时。通过尽量减少与 any 复杂 API 和环境(不仅仅是门户)的接触,而不是与 API 分离,您将更深入地了解您的代码。
一个解决方案是在 portlet 类 中进行非常简单的连接(并对此进行代码审查),同时将可测试代码提取到它自己的代码中 - 经过全面测试 - 类 不会调用外部 API,而是让他们的上下文传入。
这会给您留下一些未经单元测试的非常简单的代码,但除了代码审查之外,您还可以(并且应该)添加一些 integration/smoke 在完整环境中实际工作的测试。
有时一个简单的解决方案是快速模拟门户 类(或其他外部 类),但我不认为这是首选解决方案。一旦您开始编写重要的设置代码来准备环境,您在测试运行时将一无所获。如果它失败了,无论如何你都必须在真实环境中检查它,看看你的设置是否准确。
抱歉,如果这是个坏消息 - 恕我直言,当您有任何给定的 API 尚未构建且无法在单元测试中替换时,这是固有的。而且我不愿意在 unit 测试中例行进行大型设置例程。如果这种情况经常发生,我不会称它们为单元测试——而是将(太复杂的)单元分解成更小的单元。或者接受两个不同 APIs.
之间的简单接线(适配)代码的代码审查