1. Overview
1.概述
Arquillian is a container-agnostic integration testing framework for Jakarta EE. Using Arquillian minimizes the burden of managing containers, deployments, framework initializations, and so on.
Arquillian是一个适用于Jakarta EE的容器无关的集成测试框架。使用Arquillian可以最大限度地减少管理容器、部署、框架初始化等方面的负担。
We can focus on writing actual tests and not on bootstrapping the test environment.
我们可以专注于编写实际的测试,而不是启动测试环境。
2. Core Concepts
2.核心概念
2.1. Deployment Archives
2.1.部署档案
There is an easy way for testing our application when running inside a container.
在容器内运行时,有一个简单的方法来测试我们的应用程序。
Firstly, ShrinkWrap class provides an API to create deployable *.jar, *.war, and *.ear files.
首先,ShrinkWrap 类提供了一个API来创建可部署的*.jar, *.war,和*.ear文件。
Then, Arquillian allows us to configure the test deployment using the @Deployment annotation – on a method that returns a ShrinkWrap object.
然后,Arquillian允许我们使用@Deployment注解配置测试部署–在一个返回ShrinkWrap对象的方法上。
2.2. Containers
2.2.容器
Arquillian distinguishes three different types of containers:
Arquillian区分了三种不同类型的容器。
- Remote – tested using a remote protocol like JMX
- Managed – remote containers but their lifecycle is managed by Arquillian
- Embedded – local containers where tests are performed using local protocols
Also, we can classify containers by their capabilities:
此外,我们还可以根据容器的能力进行分类。
- Jakarta EE applications deployed on an application server like Glassfish or JBoss
- Servlet containers deployed on Tomcat or Jetty
- Standalone containers
- OSGI containers
It examines the runtime classpath and automatically selects the available container.
它检查运行时classpath并自动选择可用的容器。
2.3. Test Enrichment
2.3.测试充实
Arquillian enriches tests by providing e.g. the dependency injection so that we can write our tests easily.
Arquillian通过提供例如依赖性注入来丰富测试,这样我们就可以轻松地编写我们的测试。
We can inject dependencies using @Inject, inject resources with @Resource, EJB session beans using @EJB, etc.
我们可以用@Inject来注入依赖,用@Resource来注入资源,用@EJB,来注入EJB会话Bean等等。
2.4. Multiple Test Runners
2.4.多个测试运行器
We can create multiple deployments using the annotation:
我们可以使用注解来创建多个部署。
@Deployment(name="myname" order = 1)
Where the name is the name of the deployment file and the order parameter is the execution order of the deployment, so we can now run tests on multiples deployments at the same time using the annotation:
其中name是部署文件的名称,order参数是部署的执行顺序,所以我们现在可以使用注解在多个部署上同时运行测试。
@Test @OperateOnDeployment("myname")
The before test is executed on the myname deployment container using the order defined in the @Deployment annotation.
使用@Deployment注解中定义的顺序,在myname部署容器上执行 Before 测试。
2.5. Arquillian Extensions
2.5.阿尔基里安的扩展
Arquillian offers multiple extensions in case our testing needs aren’t covered by the core runtime. We have persistence, transactions, client/server, REST extensions, etc.
Arquillian提供了多种扩展,以备我们的测试需求不被核心运行时所覆盖。我们有持久性、事务、客户/服务器、REST扩展等。
We can enable those extensions by adding appropriate dependencies to Maven or Gradle config files.
我们可以通过在Maven或Gradle配置文件中添加适当的依赖项来启用这些扩展。
Commonly used extensions are Drone, Graphene, and Selenium.
常用的扩展是Drone、Graphene和Selenium。
3. Maven Dependencies and Setup
3.Maven的依赖性和设置
Let’s add the following dependency to our pom.xml file:
让我们在我们的pom.xml文件中添加以下依赖关系。
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.1.13.Final</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>4.1.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.container</groupId>
<artifactId>arquillian-glassfish-embedded-3.1</artifactId>
<version>1.0.0.Final</version>
<scope>test</scope>
</dependency>
The latest version of the dependencies can be found here: arquillian-bom, org.glassfish.main.extras, org.jboss.arquillian.container.
最新版本的依赖项可以在这里找到。arquillian-bom, org.glassfish.main.extras, org.jboss.arquillian.container。
4. Simple Test
4.简单测试
4.1. Create a Component
4.1.创建一个组件
Let’s start with a simple component. We do not include any advanced logic here to be able to focus on tests:
让我们从一个简单的组件开始。我们在这里不包括任何高级逻辑,以便能够专注于测试。
public class Component {
public void sendMessage(PrintStream to, String msg) {
to.println(message(msg));
}
public String message(String msg) {
return "Message, " + msg;
}
}
Using Arquillian, we want to test that this class behaves correctly when invoked as a CDI bean.
使用Arquillian,我们想测试这个类在作为CDI Bean调用时的行为是否正确。
4.2. Write Our First Arquillian Test
4.2.编写我们的第一个Arquillian测试
First, we need to specify that our test class should be run using the framework-specific runner:
首先,我们需要指定我们的测试类应该使用特定框架的运行器运行。
@RunWith(Arquillian.class)
If we’re going to run our tests inside a container, we need to use the @Deployment annotation.
如果我们要在容器内运行我们的测试,我们需要使用@Deployment注解。
Arquillian does not use the entire classpath to isolate the test archive. Instead, it uses the ShrinkWrap class, that is a Java API for creating archives. When we create the archive to test, we specify what files to include in the classpath to use the test. During the deployment, ShrinkWrap isolates only the classes needed for the test.
Arquillian不使用整个classpath来隔离测试存档。相反,它使用ShrinkWrap类,那是一个用于创建归档的Java API。当我们创建要测试的归档文件时,我们指定在classpath中包括哪些文件来使用测试。在部署过程中,ShrinkWrap只隔离了测试所需的类。
Using the addclass() method we can specify all necessary classes, and also add an empty manifest resource.
使用addclass()方法,我们可以指定所有必要的类,还可以添加一个空清单资源。
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:
JavaArchive.class创建了一个名为test.war的模拟网络档案,该文件被部署到容器中,然后被Arquillian用来执行测试。
@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.测试企业级Java Bean
5.1. Enterprise Java Bean
5.1.企业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:
通过Arquillian,我们可以测试企业Java Bean的依赖注入,为此我们创建了一个类,该类有一个将任何单词转换为小写的方法。
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:
CapsConvertor类被注入到一个服务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
5.2.测试企业Java Bean
Now we can use Arquillian to test our enterprise Java Bean, injecting the CapsService:
现在我们可以使用Arquillian来测试我们的企业Java Bean,注入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:
使用ShrinkWrap,我们确保所有的类都被正确地连接起来。
@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.测试JPA
6.1. Persistence
6.1.持久性
We can also use Arquillian to test persistence. First, we are going to create our entity:
我们也可以使用Arquillian来测试持久性。首先,我们要创建我们的实体。
@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:
然后,我们将创建我们的EJB来对我们的数据进行基本操作。
@Stateless
public class CarEJB {
@PersistenceContext(unitName = "defaultPersistenceUnit")
private EntityManager em;
public Car saveCar(Car car) {
em.persist(car);
return car;
}
public List<Car> findAllCars() {
Query query
= em.createQuery("SELECT b FROM Car b ORDER BY b.name ASC");
List<Car> 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.
通过saveCar,我们可以将汽车名称保存到数据库中,通过findAllCars,我们可以获得所有存储的汽车,还可以通过deleteCar从数据库中删除一辆汽车。
6.2. Test Persistence With Arquillian
6.2.用Arquillian测试持久性
Now we can perform some basic tests using Arquillian.
现在我们可以使用Arquillian进行一些基本测试。
First, we add our classes to our ShrinkWrap:
首先,我们将我们的类添加到我们的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 this test, we first create four car instances, and we check that the number of rows in the database is the same we created.
在这个测试中,我们首先创建四个汽车实例,并检查数据库中的行数是否与我们创建的相同。
8. Conclusion
8.结论
In this tutorial, we:
在本教程中,我们。
- introduced Arquillian core concepts
- injected a component into the Arquillian test
- tested an EJB
- tested persistence
- performed the Arquillian test using Maven
You can find the code from the article over on Github.
你可以从Github上的文章中找到代码。