2016-04-01 17 views
3

Ich arbeite an einer Java EE 7 (auf Wildfly 9.0.2) Anwendung und stolperte über einen Artikel http://www.oracle.com/technetwork/articles/java/intondemand-1444614.html. Hauptsächlich über:EJB No Interface View Test (Arquillain & Mockito)

vorzeitigen Extensibility ist die Wurzel etwas Böseen

Dieses Gefühl in bestimmten Fällen macht mir begegnet ist. Ich habe einige Klassen in eine No-Interface-Ansicht geändert. Die Implementierung selbst ist kein Problem, Testen ist jedoch.

Zum Beispiel habe ich diese 2 Klassen.

@Stateless 
public class SomeBean { 
    public String getText() 
    { 
     return "Test text"; 
    } 
} 

Und

@Stateless 
public class SomeOtherBean { 
    @Inject 
    private SomeBean someBean; 

    public String getText() 
    { 
     return someBean.getText(); 
    } 
} 

Ich möchte irgendwie, dass die someBean Eigenschaft mit vorzugsweise verspottet Objekt überschrieben. Ohne die SomeBean und SomeOtherBean Klasse zu ändern. Ich habe einige Beispiele versucht, aber sie funktionierten nicht zum Beispiel: https://github.com/arquillian/arquillian-showcase/tree/master/extensions/autodiscover/src/test/java/org/jboss/arquillian/showcase/extension/autodiscover

Hat jemand dieses vorher getroffen und eine Lösung gehabt?

Antwort

3

Ich endete mit 2 Lösungen.

Lösung 1: Verwenden Mockito für interne oder kleinere Tests

für eine bestimmte Klasse Mockito Prüfung ist wirklich nützlich, da es Dependency Injection unterstützt.

@RunWith(MockitoJUnitRunner.class) 
public class SomeOtherBeanTest { 
    @Mock 
    private SomeBean someBean; 

    @InjectMocks 
    private SomeOtherBean someOhterBean; 

    @Before 
    public void setUp() { 
     Mockito.when(someBean.getText()).thenReturn("Overwritten!"); 
    } 

    @Test 
    public void testGetText() throws Exception { 
     assertEquals("Overwritten!", someOhterBean.getText()); 
    } 
} 

Lösung 2: Verwenden Sie @Produces und @Alternatives für externe Dienstleistungen spöttischen (zB spöttischen OAuth2 Server) oder größer Test (zB Integrationstests)

Zuerst habe ich erstellen Sie eine neue @Alternative Anmerkung:

@Alternative 
@Stereotype 
@Retention(RUNTIME) 
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) 
public @interface CDIMock {} 

Dann fügen Sie diese als Klischee auf den Arquillian beans.xml Einsatz:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" 
     bean-discovery-mode="all"> 
    <alternatives> 
     <stereotype>com.project.CDIMock</stereotype> 
    </alternatives> 
</beans> 

Danach eine neue @Producer Methode in einer separaten Klasse erstellen:

public class SomeBeanMockProducer { 
    @Produces @CDIMock 
    public static SomeBean produce() { 
     SomeBean someBean = Mockito.mock(SomeBean.class); 
     Mockito.when(someBean.getText()).thenReturn("mocked"); 

     return someBean; 
    } 
} 

die SomeBeanMockProducer Klasse zur Arquillian Bereitstellung hinzufügen und Sie sollten daran zu arbeiten haben.

Eine Alternative zu dieser Lösung ist die Verwendung von @Specializes und die Erweiterung der SomeBean-Implementierung. Meiner Meinung nach gibt mir das nicht genug Kontrolle wie die @Alternative + Mocking-Lösung (@CDIMock in meinem Beispiel).

Zum Beispiel sagen wir I SomeBean hat Methoden, die Remote-Server aufruft. Wenn ich eine Methode hinzufügen und zu @override in der @Specializes Klasse vergessen, wird es eine echte Remote-Aufruf machen, wird dies nicht mit Mocking der Fall sein.

0

Es ist offensichtlich, dass das Ersetzen eines Mock oder eines anderen spezialisierten Objekts für eine injizierte No-Interface-Klasse schwieriger ist, da dies genau das ist, was Sie wollten, indem Sie keine Schnittstelle für die Bean deklarieren.

Having said that, wenn Sie nicht einen CDI-Container (z. B. tun POJO-Unit-Tests) Ich denke, Mockito ist der einfachste Weg.

Wenn Sie den "reinen CDI" Weg innerhalb eines Containers machen wollen, können Sie die Alternative und Spezialisierungsmechanismen von CDI verwenden, wie in der Java EE 6 tutorial beschrieben.

@Specializes 
public class SomeBeanMock extends SomeBean { 

    @Overrides   
    public String getText() 
    { 
     return "mock"; 
    } 
} 

Natürlich können Sie nur Mocks verwenden können, die die ursprüngliche Bohne Unterklasse (da Sie keine Schnittstelle haben), und Sie werden zu den üblichen Sichtbarkeitsregeln beschränkt. Ändern/Mocking private Feld oder Methoden erfordern Reflexion oder Bytecode-Manipulation (was Mockito hinter den Kulissen tut).

+0

Danke für Ihren Kommentar. Ich endete mit der '@ Alternative' Lösung + @Produces. Dies erlaubt mir, es richtig zu verspotten. Ich habe meine Antwort aktualisiert, wie ich sie benutzt habe. –