Pregunta

Estoy intentando añadir algunas pruebas de unidad a una aplicación JSF. Esto ni aplicación dependen en gran medida las mejores prácticas, por lo que muchos métodos de servicios utilizan la FacesContext a los datos de extracción de beans de sesión administrados de esta manera:

(esto es dentro de un util clase)

  public static Object getPageBean(String beanReference) {
      FacesContext fc = FacesContext.getCurrentInstance();
      VariableResolver vr = fc.getApplication().getVariableResolver();
      return vr.resolveVariable(fc, beanReference);
  }

¿Cuál sería la mejor manera de burlarse de esto? Estoy utilizando maravilloso, así que tengo unas cuantas más opciones para crear clases que normalmente me puedo crear.

¿Fue útil?

Solución 5

en mi caso yo era capaz de burlarse de ella en el maravilloso puro. i proporcionar un mapa de MockBeans que pueda volver:

private FacesContext getMockFacesContext(def map){
        def fc = [
          "getApplication": {
            return ["getVariableResolver": {
              return ["resolveVariable": { FacesContext fc, String name ->
                return map[name]
              }] as VariableResolver
            }] as Application
          },
          "addMessage": {String key, FacesMessage val ->
            println "added key: [${key}] value: [${val.getDetail()}] to JsfContext messages"
          },
          "getMessages": {return null}
        ] as FacesContext;
        return fc;
      }

Otros consejos

Se puede devolver un contexto simulada a través de FacesContext.getCurrentInstance invocando setCurrentInstance(FacesContext) antes de ejecutar la prueba. El método está protegido, pero se puede acceder a él a través de la reflexión o bien mediante la extensión de FacesContext. Hay una implementación de ejemplo usando Mockito aquí .

Esta URL proporciona un artículo muy bueno en él: http://illegalargumentexception.blogspot.com/2011 /12/jsf-mocking-facescontext-for-unit-tests.html

Usted tiene su bean administrado:

 package foo;

import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@RequestScoped
public class AlphaBean {
  public String incrementFoo() {
    Map<String, Object> session = FacesContext.getCurrentInstance()
        .getExternalContext()
        .getSessionMap();
    Integer foo = (Integer) session.get("foo");
    foo = (foo == null) ? 1 : foo + 1;
    session.put("foo", foo);
    return null;
  }
}

apagar la FacesContext:

package foo.test;

import javax.faces.context.FacesContext;

import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public abstract class ContextMocker extends FacesContext {
  private ContextMocker() {
  }

  private static final Release RELEASE = new Release();

  private static class Release implements Answer<Void> {
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
      setCurrentInstance(null);
      return null;
    }
  }

  public static FacesContext mockFacesContext() {
    FacesContext context = Mockito.mock(FacesContext.class);
    setCurrentInstance(context);
    Mockito.doAnswer(RELEASE)
        .when(context)
        .release();
    return context;
  }
}

A continuación, escriba su prueba de unidad:

@Test
  public void testIncrementFoo() {
    FacesContext context = ContextMocker.mockFacesContext();
    try {
      Map<String, Object> session = new HashMap<String, Object>();
      ExternalContext ext = mock(ExternalContext.class);
      when(ext.getSessionMap()).thenReturn(session);
      when(context.getExternalContext()).thenReturn(ext);

      AlphaBean bean = new AlphaBean();
      bean.incrementFoo();
      assertEquals(1, session.get("foo"));
      bean.incrementFoo();
      assertEquals(2, session.get("foo"));
    } finally {
      context.release();
    }
  }

Se puede utilizar, por ejemplo, PowerMock , que es un marco que permite extender las bibliotecas simulacros como Mockito con capacidades adicionales. En este caso se le permite burlarse de los métodos estáticos de FacesContext.

Si está utilizando Maven, el uso siguiente enlace para comprobar la necesaria la dependencia de configuración.

Anotar su clase de prueba JUnit el uso de estos dos anotaciones. La primera anotación dice JUnit para realizar el test con PowerMockRunner. La segunda anotación dice PowerMock para preparar burlarse de la clase FacesContext.

@RunWith(PowerMockRunner.class)
@PrepareForTest({ FacesContext.class })
public class PageBeanTest {

Mock FacesContext usando PowerMock y el uso verify() de Mockito con el fin de comprobar que resolveVariable() fue llamado con los parámetros esperados.

@Test
public void testGetPageBean() {
    // mock all static methods of FacesContext
    PowerMockito.mockStatic(FacesContext.class);

    FacesContext facesContext = mock(FacesContext.class);
    when(FacesContext.getCurrentInstance()).thenReturn(facesContext);

    Application application = mock(Application.class);
    when(facesContext.getApplication()).thenReturn(application);

    VariableResolver variableResolver = mock(VariableResolver.class);
    when(application.getVariableResolver()).thenReturn(variableResolver);

    PageBean.getPageBean("bean_reference");

    verify(variableResolver)
            .resolveVariable(facesContext, "bean_reference");
}

He creado una entrada de blog lo que explica el ejemplo de código anterior con más detalle.

Te dan un ejemplo para burlarse FacesConext sin utilizar PowerMockito. La idea es extender una clase simple de FacesContext, y cambiar la instancia actual usando el método estático protegido setCurrentInstance:

import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import com.sun.faces.config.InitFacesContext;

public class DummyTest {

    @Mock
    private FacesContext context;

    @Before
    public void before(){
        MockitoAnnotations.initMocks(this);
        ServletContext sc = mock(ServletContext.class);
        new FakeContext(sc);
        assertEquals(context, FacesContext.getCurrentInstance());
    }

    @Test
    public void dummy(){

    }

    private class FakeContext extends InitFacesContext{

        public FakeContext(ServletContext sc) {
            super(sc);
            setCurrentInstance(context);
        }

    }

}

Aquí hay otra manera de utilizar Mockito y reflexión para burlarse FacesContext y seguro para realizar llamadas normales a FacesContext.getCurrentInstance () devuelve la instancia (burlado) que desee:

@Before
public void setUp() {

    // Use Mockito to make our Mocked FacesContext look more like a real one
    // while making it returns other Mocked objects
    ExternalContext externalContext = Mockito.mock(ExternalContext.class);
    Flash flash = Mockito.mock(Flash.class);
    FacesContext facesContext = Mockito.mock(FacesContext.class);
    Mockito.when(facesContext.getExternalContext()).thenReturn(externalContext);
    Mockito.when(externalContext.getFlash()).thenReturn(flash);

    // Use Java reflection to set the FacesContext to our Mock, since
    // FacesContext.setCurrentInstance() is protected.
    try {
        Method setter = FacesContext.class.getDeclaredMethod("setCurrentInstance", new Class[]{FacesContext.class});
        setter.setAccessible(true);
        setter.invoke(null, new Object[]{facesContext});
    } catch (Exception e) {
        System.err.println("Exception in reflection-based access to FacesContext");
        e.printStackTrace();
    }
}

(Este está adaptado / extendida de @ respuesta de McDowell a continuación.)

Creo que la mejor solución no se presenta aquí. Aquí vamos

@RunWith(PowerMockRunner.class)
@PrepareForTest({ FacesContext.class})
public class MyTestClass{

@Mock
private FacesContext facesContext;

@Before
public void init() throws Exception {
        PowerMockito.mockStatic(FacesContext.class);
        PowerMockito.when(FacesContext.getCurrentInstance()).thenReturn(facesContext);
}

Y tiene que importar todo el paquete en su PowerMockito pom.xml

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>${mockito.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top