2017-09-10 4 views
0

J'utilise TomEE avec Intellij pour tester mes beans EJB/JPA. J'ai vu sur this answer que je devrais utiliser un conteneur intégré pour tester. J'ai découvert Arquillian au this other answer (à partir de la même question) mais comme indiqué sur les commentaires, il est difficile de mettre en place et pas convivial, des choses que les débutants comme moi recherchent.Comment tester EJB avec TomEE?

Malheureusement je n'utilise pas la dépendance glassfish-embedded-all comme réponse, mais tomee-embedded. J'ai vu sur ce official tutorial il devrait utiliser JTA ainsi que répondu ci-dessus. Mais pourquoi?

Faire en dernier lien, je recevais cette erreur:

No EJBContainer provider available: no provider names had been found. 

Ensuite, en utilisant un morceau de code @BeforeClass méthode de cette answer. Mon test est illustré ci-dessous:

Properties properties = new Properties(); 
    properties.setProperty(EJBContainer.PROVIDER, "tomee-embedded"); 
    EJBContainer container = EJBContainer.createEJBContainer(properties); 
    AccountDao dao = (AccountDao) container.getContext().lookup("java:global/Test/AccountDao"); 

Test est mon nom d'application et AccountDao est mon Stateless Bean que je veux tester. Mais maintenant, je reçois cette erreur:

Caused by: org.hsqldb.HsqlException: user lacks privilege or object not found: PG_CLASS 

Bien que je ne suis pas en utilisant HSQLDB, je vais avoir cette erreur. Comment puis-je ajouter correctement des propriétés postgresql pour instancier correctement mon Hibernate entityManager? Voici mon persistence.xml:

<persistence-unit name="unitName"> 
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> 
    <class>entity.PersistentEntity.Account</class> 
    <properties> 
     <property name="tomee.jpa.factory.lazy" value="true"/> 
     <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/> 
     <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost/click10"/> 
     <property name="javax.persistence.jdbc.user" value="postgres"/> 
     <property name="javax.persistence.jdbc.password" value="postgres"/> 
     <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect"/> 
     <property name="hibernate.show_sql" value="true"/> 
     <property name="hibernate.format_sql" value="true"/> 
     <property name="hibernate.hbm2ddl.auto" value="update"/> 
    </properties> 
</persistence-unit> 

Répondre

1

J'ai eu du succès avec l'utilisation du conteneur embarqué tomee pour les tests unitaires. Comme avec n'importe quelle ressource JUnit externe, elle peut être gérée en utilisant un @Rule donc j'ai deux classes, la classe Rule et un wrapper pour l'Embedded TomEE.

Classe de wrapper pour la classe TomEE Container. Configure une source de données derby intégrée et un utilisateur afin que nous puissions tester l'authentification de base.

/** 
* class for starting an Embedded TomEE server which will scan the classpath and start the application. 
* The configuration configures an InMemory derby database, and tells JPA to create tables based on the Entity annotations 
* 
*/ 
public class EmbeddedTomEE { 

    public static final String USERNAME = "aUser"; 
    public static final String PASSWORD = "aPassword"; 
    private Container container; 

    public void start() { 
     Configuration configuration = new Configuration(); 
     Properties properties = new Properties(); 
     properties.setProperty("jdbc/UdDB", "new://Resource?type=DataSource"); 
     properties.setProperty("jdbc/UdDB.jdbcDriver", "org.apache.derby.jdbc.EmbeddedDriver"); 
     properties.setProperty("jdbc/UdDB.jdbcUrl", "jdbc:derby:memory:udb;create=true"); 
     properties.setProperty("jdbc/UdDB.username", "SA"); 
     properties.setProperty("jdbc/UdDB.password", ""); 
     properties.setProperty("jdbc/UdDB.jtaManaged", "true"); 
     properties.setProperty("persistence_unit.javax.persistence.schema-generation.database.action", "create"); 
     properties.setProperty("persistence_unit.javax.persistence.sql-load-script-source", "META-INF/testdata.sql"); 
     properties.setProperty("rest-persistence_unit.eclipselink.logging.level", "FINE"); //use 'FINE' for JPA logging 

     configuration.setProperties(properties); 
     // use a random port so we can have TomEE running parallel with tests 
     configuration.randomHttpPort(); 
     configuration.setWebXml("src/main/webapp/WEB-INF/web.xml"); 

     HashMap<String, String> users = new HashMap<>(); 
     users.put(USERNAME, PASSWORD); 
     configuration.setUsers(users); 
     HashMap<String, String> roles = new HashMap<>(); 
     roles.put("aUser", "user"); 
     configuration.setRoles(roles); 
     container = new Container(configuration).deployClasspathAsWebApp(); 
    } 

    public int getPort() { 
     return container.getConfiguration().getHttpPort(); 
    } 

    public void stop() { 
     container.close(); 
    } 
} 

La règle JUnit qui prend soin de démarrer le TomEE incorporé avant chaque test est exécuté. Nous avons également une certaine logique pour éviter le coût de démarrage et d'arrêt du conteneur à chaque test. La classe crée également un WebClient JAX-RS qui peut être utilisé pour effectuer des appels aux services REST des applications.

/** 
* JUnit rule for running an EmbeddedTomEE in memory. The rule has static state, this is to avoid starting and stopping the embedded container 
* with every test. Every time no test are running we start a timer, which is canceled if another test is started. This way the rule works well for a 
* single test run inside an IDE, and running multiple tests from Maven. 
* 
*/ 
public class EmbeddedTomEERule extends ExternalResource { 

    private static EmbeddedTomEE tomEE; 
    private static final AtomicInteger count = new AtomicInteger(); 
    private static Timer timer; 

    @Override 
    protected void before() throws Throwable { 
     startIfNeeded(); 
     if (timer != null) { 
      timer.cancel(); 
     } 
     count.incrementAndGet(); 
    } 

    @Synchronized 
    private void startIfNeeded() { 
     if (tomEE == null) { 
      tomEE = new EmbeddedTomEE(); 
      tomEE.start(); 
      Runtime.getRuntime().removeShutdownHook(new Thread(() -> tomEE.stop())); 
     } 
    } 

    @Override 
    protected void after() { 
     int runningTests = count.decrementAndGet(); 
     if (runningTests == 0) { 
      // stop after some time if no new test are started 
      timer = new Timer(); 
      timer.schedule(new StopEmbeddedContainer(), 10000); 
     } 
    } 

    public int getPort() { 
     return tomEE.getPort(); 
    } 

    /** 
    * creates a new WebClient that can request data from the specified path 
    */ 
    public WebClient getWebClient(String path, MediaType mediatype) { 
     WebClient client = WebClient.create("http://localhost:" + tomEE.getPort() + "/", Collections.singletonList(new JohnzonProvider()), 
       EmbeddedTomEE.USERNAME, EmbeddedTomEE.PASSWORD, null) 

       .path(path).accept(mediatype); 
     return client; 
    } 

    private static class StopEmbeddedContainer extends TimerTask { 
     @Override 
     public void run() { 
      tomEE.stop(); 
     } 
    } 
} 

Voici un exemple de la façon dont un test regarderait

public class ExampleTest { 

    @Rule 
    public EmbeddedTomEERule rule = new EmbeddedTomEERule(); 

    @Test 
    public void doTest() { 

     WebClient client = rule.getWebClient("some-endpoint", MediaType.APPLICATION_JSON_TYPE); 
     Output dto = client.get(Input.class); 
    } 
} 

Ce type de test permet de tester votre application à la couche HTTP, et il vous permet de placer des points d'arrêt dans les deux essais et le code du serveur. Techniquement, ça peut être un peu exagéré d'appeler cela un test unitaire, mais je préfère ce type de test lorsque je teste plus d'un composant. Puisque vous avez besoin d'un TomEE entièrement fonctionnel, vous devrez fournir un certain nombre de dépendances externes, dans mon cas cela ressemblait à ceci:

<dependency> 
    <groupId>org.apache.derby</groupId> 
    <artifactId>derby</artifactId> 
    <version>${derby.db.version}</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.apache.tomee</groupId> 
    <artifactId>openejb-core</artifactId> 
    <version>${openejb-core.version}</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.apache.tomee</groupId> 
    <artifactId>openejb-cxf-rs</artifactId> 
    <version>${openejb-core.version}</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.apache.tomee</groupId> 
    <artifactId>openejb-server</artifactId> 
    <version>${openejb-core.version}</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.apache.tomee</groupId> 
    <artifactId>openejb-rest</artifactId> 
    <version>${openejb-core.version}</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.apache.tomee</groupId> 
    <artifactId>tomee-embedded</artifactId> 
    <version>${openejb-core.version}</version> 
    <scope>test</scope> 
</dependency> 
<dependency> 
    <groupId>org.glassfish.web</groupId> 
    <artifactId>el-impl</artifactId> 
    <version>2.2</version> 
    <scope>test</scope> 
</dependency>