visual unit tools test studio run microsoft create automatic aaa unit-testing jsf groovy mocking facescontext

unit testing - unit - Caras burlonasContexto



unit test microsoft (7)

Estoy tratando de agregar algunas pruebas unitarias a una aplicación JSF. Esta aplicación no se basó en gran medida en las mejores prácticas, por lo que muchos métodos de servicio utilizan FacesContext para extraer datos de beans de sesión administrados, como por ejemplo:

(Esto es dentro de una clase util)

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 usando groovy, así que tengo algunas opciones más para crear clases que normalmente no puedo crear.


Aquí hay otra forma de usar Mockito y la reflexión para simular FacesContext y asegurarse de que las llamadas normales a FacesContext.getCurrentInstance () devuelvan la instancia (simulada) que desea:

@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(); } }

(Esto está adaptado / extendido de la 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 necesitas importar todo el paquete de PowerMockito en tu 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>


En mi caso, fui capaz de burlarme de él en puro groovy. Proporciono un mapa de MockBeans que puede devolver:

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; }


Esta url proporciona un artículo realmente bueno: http://illegalargumentexception.blogspot.com/2011/12/jsf-mocking-facescontext-for-unit-tests.html

Tienes tu bean gestionado:

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; } }

Usted apaga el 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; } }

Luego escribe tu 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(); } }


Podría usar, por ejemplo, PowerMock, que es un marco que le permite extender bibliotecas simuladas como Mockito con capacidades adicionales. En este caso, te permite FacesContext métodos estáticos de FacesContext .

Si está utilizando Maven, use el siguiente link para verificar la configuración de dependencia necesaria.

Anota tu clase de prueba JUnit usando estas dos anotaciones. La primera anotación le dice a JUnit que ejecute la prueba usando PowerMockRunner . La segunda anotación le dice a PowerMock que se prepare para burlarse de la clase FacesContext .

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

FacesContext simulacro de FacesContext utilizando PowerMock y use Verify verify() de Mockito para verificar que se resolveVariable() llamado a la resolveVariable() 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 publicación de blog que explica el ejemplo de código anterior con más detalle.


Puede devolver un contexto simulado a través de FacesContext.getCurrentInstance invocando setCurrentInstance(FacesContext) antes de ejecutar la prueba. El método está protegido, pero puede acceder a él a través de la reflexión o extendiendo FacesContext . Hay una implementación de ejemplo usando Mockito here .


Te doy un ejemplo para burlarte de FacesConext sin usar PowerMockito. La idea es extender una clase simple desde 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); } } }