2010-11-23 31 views
13

Ich versuche einige Komponententests zu einer JSF-Anwendung hinzuzufügen. Diese Anwendung didnt stark auf allem Best Practices verlassen, verwenden Sie so viele Service-Methoden, um die FacesContext Daten der verwalteten Session Beans zu ziehen, wie so:Mocking FacesContext

(dies innerhalb einer util Klasse)

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

Was wäre die Der beste Weg, das zu verspotten? Ich benutze groovy, also habe ich ein paar mehr Optionen zum Erstellen von Klassen, die ich normalerweise nicht erstellen kann.

Antwort

2

in meinem Fall konnte ich es in pure groovy verspotten. i bieten eine Karte von MockBeans, die es zurückgeben kann:

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

Interessant. Ich muss vielleicht Groovy genauer unter die Lupe nehmen. – BalusC

+0

Das einzige Problem mit diesem Ansatz ist, dass ich alle Methoden hinzufügen muss, die ich für das Mock-Objekt verwenden möchte – mkoryak

9

Sie können ein Mock Kontext über FacesContext.getCurrentInstance von setCurrentInstance(FacesContext) Aufruf zurück, bevor der Test ausgeführt wird. Die Methode ist geschützt, aber Sie können entweder über Reflektion oder durch Erweitern FacesContext darauf zugreifen. Es gibt eine Beispielimplementierung, die Mockito here verwendet.

3

Diese URL bietet einen wirklich guten Artikel über sie: http://illegalargumentexception.blogspot.com/2011/12/jsf-mocking-facescontext-for-unit-tests.html

Sie haben Ihre Managed Bean:

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

Sie die Faces Stub:

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

Dann wird Ihr Gerät schreiben Test:

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

Sie könnten zum Beispiel PowerMock verwenden, das ein Framework ist, das es ermöglicht, Mock-Bibliotheken wie Mockito mit zusätzlichen Funktionen zu erweitern. In diesem Fall können Sie die statischen Methoden von FacesContext verspotten.

Wenn Sie Maven verwenden, verwenden Sie die folgenden link, um die erforderliche Abhängigkeitseinstellung zu überprüfen.

Beschriften Sie Ihre JUnit-Testklasse mit diesen beiden Anmerkungen. Die erste Anmerkung weist JUnit an, den Test unter Verwendung von PowerMockRunner auszuführen. Die zweite Anmerkung teilt PowerMock mit, sich auf die Klasse FacesContext zu verspotten.

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

Mock FacesContext mit PowerMock und verify() von Mockito verwenden, um zu überprüfen, ob resolveVariable() mit den erwarteten Parametern aufgerufen wurde.

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

Ich habe ein blog post erstellt, die das obige Codebeispiel näher erläutert.

2

Ich gebe Ihnen ein Beispiel, um FacesConext zu verspotten, ohne PowerMockito zu verwenden.Die Idee ist, eine einfache Klasse von Faces, zu erweitern und die aktuellen Instanz mit geschützter statischer setCurrentInstance Methode ändern:

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

    } 

} 
0

Ich glaube, die beste Lösung ist hier nicht dargestellt. Hier gehen wir

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

Und Sie brauchen alle PowerMockito Bündel in Ihrer 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> 
1

Hier ist eine andere Art und Weise zu importieren Mockito und Reflexion zu verwenden, zu verspotten und Faces sicher normale Anrufe zu Faces machen .getCurrentInstance() gibt die (verspottet) Instanz, die Sie wollen:

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

(Diese angepasst ist/erstreckte sich von @ McDowell Antwort weiter unten.)