Introduzione al test con Arquillian

1. Panoramica

Arquillian è un framework di test di integrazione indipendente dal contenitore per Jakarta EE. L'utilizzo di Arquillian riduce al minimo il carico di gestione di container, implementazioni, inizializzazioni di framework e così via.

Possiamo concentrarci sulla scrittura di test effettivi e non sul bootstrap dell'ambiente di test.

2. Concetti fondamentali

2.1. Archivi di distribuzione

C'è un modo semplice per testare la nostra applicazione durante l'esecuzione all'interno di un contenitore.

In primo luogo, la classe ShrinkWrap fornisce un'API per creare file * .jar, * .war e * .ear distribuibili .

Quindi, Arquillian ci consente di configurare la distribuzione di test utilizzando l' annotazione @Deployment - su un metodo che restituisce un oggetto ShrinkWrap .

2.2. Contenitori

Arquillian distingue tre diversi tipi di contenitori:

  • Remoto: testato utilizzando un protocollo remoto come JMX
  • Gestito: container remoti ma il loro ciclo di vita è gestito da Arquillian
  • Incorporato: contenitori locali in cui i test vengono eseguiti utilizzando protocolli locali

Inoltre, possiamo classificare i contenitori in base alle loro capacità:

  • Applicazioni Jakarta EE distribuite su un server delle applicazioni come Glassfish o JBoss
  • Contenitori servlet distribuiti su Tomcat o Jetty
  • Contenitori autonomi
  • Contenitori OSGI

Esamina il classpath di runtime e seleziona automaticamente il contenitore disponibile.

2.3. Arricchimento del test

Arquillian arricchisce i test fornendo, ad esempio, l'inserimento delle dipendenze in modo che possiamo scrivere facilmente i nostri test.

Possiamo iniettare dipendenze usando @Inject , iniettare risorse con @Resource , bean di sessione EJB usando @EJB, ecc.

2.4. Più test runner

Possiamo creare più distribuzioni utilizzando l'annotazione:

@Deployment(name="myname" order = 1)

Dove il nome è il nome del file di distribuzione e il parametro order è l'ordine di esecuzione della distribuzione, quindi ora possiamo eseguire test su più distribuzioni contemporaneamente utilizzando l'annotazione:

@Test @OperateOnDeployment("myname")

Il test prima viene eseguito sul contenitore di distribuzione myname utilizzando l'ordine definito nell'annotazione @Deployment .

2.5. Estensioni Arquillian

Arquillian offre più estensioni nel caso in cui le nostre esigenze di test non siano coperte dal runtime principale. Abbiamo persistenza, transazioni, client / server, estensioni REST, ecc.

Possiamo abilitare queste estensioni aggiungendo le dipendenze appropriate ai file di configurazione di Maven o Gradle.

Le estensioni comunemente utilizzate sono Drone, Graphene e Selenium.

3. Dipendenze e installazione di Maven

Aggiungiamo la seguente dipendenza al nostro file pom.xml :

 org.jboss.arquillian arquillian-bom 1.1.13.Final import pom   org.glassfish.main.extras glassfish-embedded-all 4.1.2 test   org.jboss.arquillian.container arquillian-glassfish-embedded-3.1 1.0.0.Final test 

L'ultima versione delle dipendenze può essere trovata qui: arquillian-bom, org.glassfish.main.extras, org.jboss.arquillian.container.

4. Test semplice

4.1. Crea un componente

Cominciamo con un semplice componente. Non includiamo qui alcuna logica avanzata per poterci concentrare sui test:

public class Component { public void sendMessage(PrintStream to, String msg) { to.println(message(msg)); } public String message(String msg) { return "Message, " + msg; } }

Utilizzando Arquillian, vogliamo verificare che questa classe si comporti correttamente quando invocata come bean CDI.

4.2. Scrivi il nostro primo test Arquillian

Innanzitutto, dobbiamo specificare che la nostra classe di test deve essere eseguita utilizzando il runner specifico del framework:

@RunWith(Arquillian.class) 

Se vogliamo eseguire i nostri test all'interno di un contenitore, dobbiamo usare l' annotazione @Deployment .

Arquillian non utilizza l'intero classpath per isolare l'archivio di test. Invece, utilizza la classe ShrinkWrap , ovvero un'API Java per la creazione di archivi. Quando creiamo l'archivio da testare, specifichiamo quali file includere nel classpath per utilizzare il test. Durante la distribuzione, ShrinkWrap isola solo le classi necessarie per il test.

Usando il metodo addclass () possiamo specificare tutte le classi necessarie e anche aggiungere una risorsa manifest vuota.

The JavaArchive.class creates a mockup web archive called test.war, this file is deployed into the container and then is used by Arquillian to perform tests:

@Deployment public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(Component.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }

Then we inject our component in the test:

@Inject private Component component;

Finally, we perform our test:

assertEquals("Message, MESSAGE",component.message(("MESSAGE"))); component.sendMessage(System.out, "MESSAGE");

5. Testing Enterprise Java Beans

5.1. Enterprise Java Bean

With Arquillian we can test dependency injection of an Enterprise Java Bean, to do that we create a class that has a method for converting any word to lowercase:

public class ConvertToLowerCase { public String convert(String word){ return word.toLowerCase(); } }

Using this class, we create a stateless class for calling the method created before:

@Stateless public class CapsConvertor { public ConvertToLowerCase getLowerCase(){ return new ConvertToLowerCase(); } }

The CapsConvertor class gets injected into a service bean:

@Stateless public class CapsService { @Inject private CapsConvertor capsConvertor; public String getConvertedCaps(final String word){ return capsConvertor.getLowerCase().convert(word); } }

5.2. Test the Enterprise Java Bean

Now we can use Arquillian to test our enterprise Java Bean, injecting the CapsService:

@Inject private CapsService capsService; @Test public void givenWord_WhenUppercase_ThenLowercase(){ assertTrue("capitalize".equals(capsService.getConvertedCaps("CAPITALIZE"))); assertEquals("capitalize", capsService.getConvertedCaps("CAPITALIZE")); }

Using ShrinkWrap, we ensure that all classes are wired correctly:

@Deployment public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClasses(CapsService.class, CapsConvertor.class, ConvertToLowerCase.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }

6. Testing JPA

6.1. Persistence

We can also use Arquillian to test persistence. First, we are going to create our entity:

@Entity public class Car { @Id @GeneratedValue private Long id; @NotNull private String name; // getters and setters }

We have a table that holds names of cars.

Then we are going to create our EJB to perform basic operations on our data:

@Stateless public class CarEJB { @PersistenceContext(unitName = "defaultPersistenceUnit") private EntityManager em; public Car saveCar(Car car) { em.persist(car); return car; } public List findAllCars() { Query query = em.createQuery("SELECT b FROM Car b ORDER BY b.name ASC"); List entries = query.getResultList(); return entries == null ? new ArrayList() : entries; public void deleteCar(Car car) { car = em.merge(car); em.remove(car); } }

With saveCar we can save the car names into the database, we can get all cars stored with findAllCars, and also we can delete a car from the database with deleteCar.

6.2. Test Persistence With Arquillian

Now we can perform some basic tests using Arquillian.

First, we add our classes to our ShrinkWrap:

.addClasses(Car.class, CarEJB.class) .addAsResource("META-INF/persistence.xml")

Then we create our test:

@Test public void testCars() { assertTrue(carEJB.findAllCars().isEmpty()); Car c1 = new Car(); c1.setName("Impala"); Car c2 = new Car(); c2.setName("Lincoln"); carEJB.saveCar(c1); carEJB.saveCar(c2); assertEquals(2, carEJB.findAllCars().size()); carEJB.deleteCar(c1); assertEquals(1, carEJB.findAllCars().size()); }

In questo test, creiamo prima quattro istanze di auto e controlliamo che il numero di righe nel database sia lo stesso che abbiamo creato.

8. Conclusione

In questo tutorial, noi:

  • ha introdotto i concetti fondamentali di Arquillian
  • ha iniettato un componente nel test di Arquillian
  • testato un EJB
  • persistenza testata
  • ha eseguito il test di Arquillian utilizzando Maven

Puoi trovare il codice dall'articolo su Github.