[jboss-user] [JBoss Seam] - Re: UnitTesting Components
KnisterPeter
do-not-reply at jboss.com
Fri Jun 22 10:40:45 EDT 2007
Ok, below is the JUnit4 version of SeamTest. If there is interest it could be included into seam. There are only small changes which could be refactored into a subclass so both TestNG and JUnit4 share a common base class.
In details the differences are the init and shutdown methods annotated with @Configuration.
But I still have a problem: I need a mock instance for one of my beans and therefore (as stated in the docs) I extend my bean and set the @Install with a precedence of MOCK, but the mock bean is not included and started in the container. Are there examples on how to use the MOCK precedence? I haven't found any in the source and examples.
/**
| * $Id$
| */
| package de.llynch.kingpin.bean;
|
| import java.lang.reflect.Field;
| import java.util.AbstractSet;
| import java.util.Collections;
| import java.util.HashMap;
| import java.util.Iterator;
| import java.util.List;
| import java.util.Map;
| import java.util.Set;
|
| import javax.faces.application.Application;
| import javax.faces.application.FacesMessage;
| import javax.faces.component.UIViewRoot;
| import javax.faces.context.FacesContext;
| import javax.faces.event.PhaseEvent;
| import javax.faces.event.PhaseId;
| import javax.naming.InitialContext;
| import javax.naming.NamingException;
| import javax.servlet.http.Cookie;
| import javax.servlet.http.HttpServletRequest;
| import javax.servlet.http.HttpSession;
| import javax.transaction.UserTransaction;
|
| import org.hibernate.validator.ClassValidator;
| import org.hibernate.validator.InvalidValue;
| import org.jboss.seam.Component;
| import org.jboss.seam.Model;
| import org.jboss.seam.actionparam.ActionParamMethodBinding;
| import org.jboss.seam.contexts.Contexts;
| import org.jboss.seam.contexts.Lifecycle;
| import org.jboss.seam.core.Expressions;
| import org.jboss.seam.core.FacesMessages;
| import org.jboss.seam.core.Init;
| import org.jboss.seam.core.Manager;
| import org.jboss.seam.core.Pageflow;
| import org.jboss.seam.init.Initialization;
| import org.jboss.seam.jsf.AbstractSeamPhaseListener;
| import org.jboss.seam.jsf.SeamApplication11;
| import org.jboss.seam.jsf.SeamNavigationHandler;
| import org.jboss.seam.jsf.SeamPhaseListener;
| import org.jboss.seam.jsf.SeamStateManager;
| import org.jboss.seam.mock.MockApplication;
| import org.jboss.seam.mock.MockExternalContext;
| import org.jboss.seam.mock.MockFacesContext;
| import org.jboss.seam.mock.MockHttpServletRequest;
| import org.jboss.seam.mock.MockHttpSession;
| import org.jboss.seam.mock.MockLifecycle;
| import org.jboss.seam.mock.MockServletContext;
| import org.jboss.seam.servlet.ServletSessionImpl;
| import org.jboss.seam.util.Naming;
| import org.jboss.seam.util.Reflections;
| import org.jboss.seam.util.Transactions;
| import org.junit.After;
| import org.junit.AfterClass;
| import org.junit.Before;
| import org.junit.BeforeClass;
|
| /**
| * Code is copied from SeamTest which is for TestNG instead of JUnit4.
| *
| * @author Markus Wolf
| */
| public abstract class AbstractSeamTest {
|
| private static MockExternalContext externalContext;
|
| private static MockServletContext servletContext;
|
| private static MockApplication application;
|
| private static AbstractSeamPhaseListener phases;
|
| private MockHttpSession session;
|
| private static Map<String, Map> conversationViewRootAttributes;
|
| private final Map<String, Object> pageParameters = new HashMap<String, Object>();
|
| protected void setParameter(final String name, final String value) {
| this.getParameters().put(name, new String[] { value });
| }
|
| protected void setPageParameter(final String name, final Object value) {
| this.pageParameters.put(name, value);
| }
|
| protected Map<String, String[]> getParameters() {
| return ((MockHttpServletRequest) this.externalContext.getRequest())
| .getParameters();
| }
|
| protected Map<String, String[]> getHeaders() {
| return ((MockHttpServletRequest) this.externalContext.getRequest())
| .getHeaders();
| }
|
| protected HttpSession getSession() {
| return (HttpSession) this.externalContext.getSession(true);
| }
|
| protected boolean isSessionInvalid() {
| return ((MockHttpSession) this.getSession()).isInvalid();
| }
|
| /**
| * Helper method for resolving components in the test script.
| */
| protected Object getInstance(final Class clazz) {
| return Component.getInstance(clazz);
| }
|
| /**
| * Helper method for resolving components in the test script.
| */
| protected Object getInstance(final String name) {
| return Component.getInstance(name);
| }
|
| /**
| * Is there a long running conversation associated with the current request?
| */
| protected boolean isLongRunningConversation() {
| return Manager.instance().isLongRunningConversation();
| }
|
| /**
| * Search in all contexts
| */
| public Object lookup(final String name) {
| return Contexts.lookupInStatefulContexts(name);
| }
|
| /**
| * @deprecated use FacesRequest or NonFacesRequest
| * @author Gavin King
| */
| @Deprecated
| public abstract class Script extends Request {
| public Script() {
| }
|
| public Script(final String conversationId) {
| super(conversationId);
| }
| }
|
| /**
| * Script is an abstract superclass for usually anonymous inner classes that
| * test JSF interactions.
| *
| * @author Gavin King
| */
| abstract class Request {
| private String conversationId;
|
| private String outcome;
|
| private boolean validationFailed;
|
| private MockFacesContext facesContext;
|
| private String viewId;
|
| private boolean renderResponseBegun;
|
| private boolean renderResponseComplete;
|
| private boolean invokeApplicationBegun;
|
| private boolean invokeApplicationComplete;
|
| private Application application;
|
| /**
| * Override to define the name of the current principal
| *
| * @return "gavin" by default
| */
| public String getPrincipalName() {
| return "gavin";
| }
|
| /**
| * Override to define the roles assigned to the current principal
| *
| * @return a Set of all roles by default
| */
| public Set<String> getPrincipalRoles() {
| return new AbstractSet<String>() {
| @Override
| public boolean contains(final Object o) {
| return true;
| }
|
| @Override
| public Iterator<String> iterator() {
| throw new UnsupportedOperationException();
| }
|
| @Override
| public int size() {
| throw new UnsupportedOperationException();
| }
| };
| }
|
| public List<Cookie> getCookies() {
| return Collections.EMPTY_LIST;
| }
|
| /**
| * A script for a JSF interaction with no existing long-running
| * conversation.
| */
| protected Request() {
| }
|
| /**
| * A script for a JSF interaction in the scope of an existing
| * long-running conversation.
| */
| protected Request(final String conversationId) {
| this.conversationId = conversationId;
| }
|
| /**
| * Is this a non-faces request? Override if it is.
| *
| * @return false by default
| */
| protected boolean isGetRequest() {
| return false;
| }
|
| /**
| * The JSF view id of the form that is being submitted or of the page
| * that is being rendered in a non-faces request. (override if you need
| * page actions to be called, and page parameters applied)
| */
| protected String getViewId() {
| return this.viewId;
| }
|
| protected void setViewId(final String viewId) {
| this.viewId = viewId;
| }
|
| /**
| * Override to implement the interactions between the JSF page and your
| * components that occurs during the apply request values phase.
| */
| protected void applyRequestValues() throws Exception {
| }
|
| /**
| * Override to implement the interactions between the JSF page and your
| * components that occurs during the process validations phase.
| */
| protected void processValidations() throws Exception {
| }
|
| /**
| * Override to implement the interactions between the JSF page and your
| * components that occurs during the update model values phase.
| */
| protected void updateModelValues() throws Exception {
| }
|
| /**
| * Override to implement the interactions between the JSF page and your
| * components that occurs during the invoke application phase.
| */
| protected void invokeApplication() throws Exception {
| }
|
| /**
| * Set the outcome of the INVOKE_APPLICATION phase
| */
| protected void setOutcome(final String outcome) {
| this.outcome = outcome;
| }
|
| /**
| * Get the outcome of the INVOKE_APPLICATION phase
| */
| protected String getInvokeApplicationOutcome() {
| return this.outcome;
| }
|
| /**
| * Override to implement the interactions between the JSF page and your
| * components that occurs during the render response phase.
| */
| protected void renderResponse() throws Exception {
| }
|
| /**
| * Override to set up any request parameters for the request.
| *
| * @deprecated use beforeRequest()
| */
| @Deprecated
| protected void setup() {
| }
|
| /**
| * Make some assertions, after the end of the request.
| */
| protected void afterRequest() {
| }
|
| /**
| * Do anything you like, after the start of the request. Especially, set
| * up any request parameters for the request.
| */
| protected void beforeRequest() {
| this.setup();
| }
|
| /**
| * Get the view id to be rendered
| *
| * @return the JSF view id
| */
| protected String getRenderedViewId() {
| if (Init.instance().isJbpmInstalled()
| && Pageflow.instance().isInProcess()) {
| return Pageflow.instance().getPageViewId();
| } else {
| // TODO: not working right now, 'cos no mock navigation handler!
| return this.getFacesContext().getViewRoot().getViewId();
| }
| }
|
| /**
| * @deprecated use validateValue()
| */
| @Deprecated
| protected void validate(final Class modelClass, final String property,
| final Object value) {
| final ClassValidator validator = Model.forClass(modelClass)
| .getValidator();
| final InvalidValue[] ivs = validator.getPotentialInvalidValues(
| property, value);
| if (ivs.length > 0) {
| this.validationFailed = true;
| final FacesMessage message = FacesMessages.createFacesMessage(
| FacesMessage.SEVERITY_WARN, ivs[0].getMessage());
| FacesContext.getCurrentInstance().addMessage(property, /* TODO */
| message);
| FacesContext.getCurrentInstance().renderResponse();
| }
| }
|
| /**
| * Did a validation failure occur during a call to validate()?
| */
| protected boolean isValidationFailure() {
| return this.validationFailed;
| }
|
| protected FacesContext getFacesContext() {
| return this.facesContext;
| }
|
| protected String getConversationId() {
| return this.conversationId;
| }
|
| /**
| * Evaluate (get) a value binding
| */
| protected Object getValue(final String valueExpression) {
| return this.application.createValueBinding(valueExpression)
| .getValue(this.facesContext);
| }
|
| /**
| * Set a value binding
| */
| protected void setValue(final String valueExpression, final Object value) {
| this.application.createValueBinding(valueExpression).setValue(
| this.facesContext, value);
| }
|
| /**
| * Validate the value against model-based constraints return true if the
| * value is valid
| */
| protected boolean validateValue(final String valueExpression,
| final Object value) {
| final InvalidValue[] ivs = Expressions.instance().validate(
| valueExpression, value);
| if (ivs.length > 0) {
| this.validationFailed = true;
| this.facesContext.addMessage(null, FacesMessages
| .createFacesMessage(FacesMessage.SEVERITY_WARN, ivs[0]
| .getMessage()));
| return false;
| } else {
| return true;
| }
| }
|
| /**
| * Call a method binding
| */
| protected Object invokeMethod(final String methodExpression) {
| return new ActionParamMethodBinding(this.application,
| methodExpression).invoke(this.facesContext, null);
| }
|
| /**
| * @return the conversation id
| * @throws Exception
| * to fail the test
| */
| public String run() throws Exception {
| final HttpServletRequest request = new MockHttpServletRequest(
| AbstractSeamTest.this.session, this.getPrincipalName(),
| this.getPrincipalRoles(), this.getCookies().toArray(
| new Cookie[] {}));
| AbstractSeamTest.this.externalContext = new MockExternalContext(
| AbstractSeamTest.this.servletContext, request);
| this.application = new SeamApplication11(
| AbstractSeamTest.this.application);
| this.facesContext = new MockFacesContext(
| AbstractSeamTest.this.externalContext, this.application);
| this.facesContext.setCurrent();
|
| this.beforeRequest();
|
| AbstractSeamTest.this.phases.beforePhase(new PhaseEvent(
| this.facesContext, PhaseId.RESTORE_VIEW,
| MockLifecycle.INSTANCE));
|
| final UIViewRoot viewRoot = this.facesContext.getApplication()
| .getViewHandler().createView(this.facesContext,
| this.getViewId());
| this.facesContext.setViewRoot(viewRoot);
| final Map restoredViewRootAttributes = this.facesContext
| .getViewRoot().getAttributes();
| if (this.conversationId != null) {
| if (this.isGetRequest()) {
| AbstractSeamTest.this.setParameter(Manager.instance()
| .getConversationIdParameter(), this.conversationId);
| // TODO: what about conversationIsLongRunning????
| } else {
| if (AbstractSeamTest.this.conversationViewRootAttributes
| .containsKey(this.conversationId)) {
| // should really only do this if the view id matches
| // (not really possible to implement)
| final Map state = AbstractSeamTest.this.conversationViewRootAttributes
| .get(this.conversationId);
| restoredViewRootAttributes.putAll(state);
| }
| }
| }
| if (!this.isGetRequest()) {
| restoredViewRootAttributes
| .putAll(AbstractSeamTest.this.pageParameters);
| }
|
| this.updateConversationId();
|
| AbstractSeamTest.this.phases.afterPhase(new PhaseEvent(
| this.facesContext, PhaseId.RESTORE_VIEW,
| MockLifecycle.INSTANCE));
|
| if (!this.isGetRequest() && !this.skipToRender()) {
|
| AbstractSeamTest.this.phases.beforePhase(new PhaseEvent(
| this.facesContext, PhaseId.APPLY_REQUEST_VALUES,
| MockLifecycle.INSTANCE));
|
| this.applyRequestValues();
|
| this.updateConversationId();
|
| AbstractSeamTest.this.phases.afterPhase(new PhaseEvent(
| this.facesContext, PhaseId.APPLY_REQUEST_VALUES,
| MockLifecycle.INSTANCE));
|
| if (!this.skipToRender()) {
|
| AbstractSeamTest.this.phases.beforePhase(new PhaseEvent(
| this.facesContext, PhaseId.PROCESS_VALIDATIONS,
| MockLifecycle.INSTANCE));
|
| this.processValidations();
|
| this.updateConversationId();
|
| AbstractSeamTest.this.phases.afterPhase(new PhaseEvent(
| this.facesContext, PhaseId.PROCESS_VALIDATIONS,
| MockLifecycle.INSTANCE));
|
| if (!this.skipToRender()) {
|
| AbstractSeamTest.this.phases
| .beforePhase(new PhaseEvent(this.facesContext,
| PhaseId.UPDATE_MODEL_VALUES,
| MockLifecycle.INSTANCE));
|
| this.updateModelValues();
|
| this.updateConversationId();
|
| AbstractSeamTest.this.phases.afterPhase(new PhaseEvent(
| this.facesContext, PhaseId.UPDATE_MODEL_VALUES,
| MockLifecycle.INSTANCE));
|
| if (!this.skipToRender()) {
|
| AbstractSeamTest.this.phases
| .beforePhase(new PhaseEvent(
| this.facesContext,
| PhaseId.INVOKE_APPLICATION,
| MockLifecycle.INSTANCE));
|
| this.invokeApplicationBegun = true;
|
| this.invokeApplication();
|
| this.invokeApplicationComplete = true;
|
| final String outcome = this
| .getInvokeApplicationOutcome();
| this.facesContext.getApplication()
| .getNavigationHandler().handleNavigation(
| this.facesContext, null, outcome);
|
| this.viewId = this.getRenderedViewId();
|
| this.updateConversationId();
|
| AbstractSeamTest.this.phases
| .afterPhase(new PhaseEvent(
| this.facesContext,
| PhaseId.INVOKE_APPLICATION,
| MockLifecycle.INSTANCE));
|
| }
|
| }
|
| }
|
| }
|
| if (this.skipRender()) {
| // we really should look at redirect parameters here!
| } else {
|
| AbstractSeamTest.this.phases.beforePhase(new PhaseEvent(
| this.facesContext, PhaseId.RENDER_RESPONSE,
| MockLifecycle.INSTANCE));
|
| this.renderResponseBegun = true;
|
| this.renderResponse();
|
| this.renderResponseComplete = true;
|
| this.facesContext.getApplication().getStateManager()
| .saveSerializedView(this.facesContext);
|
| this.updateConversationId();
|
| AbstractSeamTest.this.phases.afterPhase(new PhaseEvent(
| this.facesContext, PhaseId.RENDER_RESPONSE,
| MockLifecycle.INSTANCE));
|
| final Map renderedViewRootAttributes = this.facesContext
| .getViewRoot().getAttributes();
| if (renderedViewRootAttributes != null) {
| final Map conversationState = new HashMap();
| conversationState.putAll(renderedViewRootAttributes);
| AbstractSeamTest.this.conversationViewRootAttributes.put(
| this.conversationId, conversationState);
| }
|
| }
|
| this.afterRequest();
|
| return this.conversationId;
| }
|
| private void updateConversationId() {
| this.conversationId = Manager.instance().getCurrentConversationId();
| }
|
| private boolean skipRender() {
| return FacesContext.getCurrentInstance().getResponseComplete();
| }
|
| private boolean skipToRender() {
| return FacesContext.getCurrentInstance().getRenderResponse()
| || FacesContext.getCurrentInstance().getResponseComplete();
| }
|
| protected boolean isInvokeApplicationBegun() {
| return this.invokeApplicationBegun;
| }
|
| protected boolean isInvokeApplicationComplete() {
| return this.invokeApplicationComplete;
| }
|
| protected boolean isRenderResponseBegun() {
| return this.renderResponseBegun;
| }
|
| protected boolean isRenderResponseComplete() {
| return this.renderResponseComplete;
| }
|
| }
|
| public class NonFacesRequest extends Request {
| public NonFacesRequest() {
| }
|
| /**
| * @param viewId
| * the view id to be rendered
| */
| public NonFacesRequest(final String viewId) {
| this.setViewId(viewId);
| }
|
| /**
| * @param viewId
| * the view id to be rendered
| * @param conversationId
| * the conversation id
| */
| public NonFacesRequest(final String viewId, final String conversationId) {
| super(conversationId);
| this.setViewId(viewId);
| }
|
| @Override
| protected final boolean isGetRequest() {
| return true;
| }
|
| @Override
| protected final void applyRequestValues() throws Exception {
| throw new UnsupportedOperationException();
| }
|
| @Override
| protected final void processValidations() throws Exception {
| throw new UnsupportedOperationException();
| }
|
| @Override
| protected final void updateModelValues() throws Exception {
| throw new UnsupportedOperationException();
| }
|
| }
|
| public class FacesRequest extends Request {
|
| public FacesRequest() {
| }
|
| /**
| * @param viewId
| * the view id of the form that was submitted
| */
| public FacesRequest(final String viewId) {
| this.setViewId(viewId);
| }
|
| /**
| * @param viewId
| * the view id of the form that was submitted
| * @param conversationId
| * the conversation id
| */
| public FacesRequest(final String viewId, final String conversationId) {
| super(conversationId);
| this.setViewId(viewId);
| }
|
| @Override
| protected final boolean isGetRequest() {
| return false;
| }
|
| }
|
| @Before
| public void begin() {
| this.session = new MockHttpSession(this.servletContext);
| }
|
| @After
| public void end() {
| if (Contexts.isEventContextActive()) {
| Lifecycle.endRequest(this.externalContext);
| }
| Lifecycle.endSession(this.servletContext, new ServletSessionImpl(
| this.session));
| this.session = null;
| }
|
| /**
| * Create a SeamPhaseListener by default. Override to use one of the other
| * standard Seam phase listeners.
| */
| protected static AbstractSeamPhaseListener createPhaseListener() {
| return new SeamPhaseListener();
| }
|
| @BeforeClass
| public static void init() throws Exception {
| application = new MockApplication();
| application.setStateManager(new SeamStateManager(application
| .getStateManager()));
| application.setNavigationHandler(new SeamNavigationHandler(application
| .getNavigationHandler()));
| // don't need a SeamVariableResolver, because we don't test the view
| phases = createPhaseListener();
|
| servletContext = new MockServletContext();
| initServletContext(servletContext.getInitParameters());
| Lifecycle.setServletContext(servletContext);
| new Initialization(servletContext).create().init();
|
| conversationViewRootAttributes = new HashMap<String, Map>();
| }
|
| @AfterClass
| public static void cleanup() throws Exception {
| if (servletContext != null)
| Lifecycle.endApplication(servletContext);
| externalContext = null;
| conversationViewRootAttributes = null;
| }
|
| /**
| * Override to set up any servlet context attributes.
| */
| public static void initServletContext(final Map initParams) {
| }
|
| protected InitialContext getInitialContext() throws NamingException {
| return Naming.getInitialContext();
| }
|
| protected UserTransaction getUserTransaction() throws NamingException {
| return Transactions.getUserTransaction();
| }
|
| /**
| * Get the value of an object field, by reflection.
| */
| protected Object getField(final Object object, final String fieldName) {
| final Field field = Reflections.getField(object.getClass(), fieldName);
| if (!field.isAccessible()) {
| field.setAccessible(true);
| }
| return Reflections.getAndWrap(field, object);
| }
|
| /**
| * Set the value of an object field, by reflection.
| */
| protected void setField(final Object object, final String fieldName,
| final Object value) {
| final Field field = Reflections.getField(object.getClass(), fieldName);
| if (!field.isAccessible()) {
| field.setAccessible(true);
| }
| Reflections.setAndWrap(field, object, value);
| }
|
| }
|
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4056913#4056913
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4056913
More information about the jboss-user
mailing list