KEMBAR78
Arquillian : An introduction | PDF
Arquillian : An introduction
      Testing with real objects
          Vineet Reynolds
            March 2012
How does this solve our problems?

WHY ARQUILLIAN?
Test Doubles redux
How did we arrive at the current
testing landscape?
Let’s test a repository
@Stateless @Local(UserRepository.class)
public class UserJPARepository implements UserRepository {

    @PersistenceContext                                      Injected by the container.
    private EntityManager em;                                How do we get one in our
                                                                       tests?

    public User create(User user) {
          em.persist(user);
                                                               How do we test this?
          return user;
    }
      ...
}
Did you say Mocks?
public class MockUserRepositoryTests {
    …
    @Before public void injectDependencies() {
        // Mock
        em = mock(EntityManager.class);
        userRepository = new UserJPARepository(em);
    }

    @Test public void testCreateUser() throws Exception {
        // Setup
        User user = createTestUser();

        // Execute
        User createdUser = userRepository.create(user);

        // Verify
        verify(em, times(1)).persist(user);
        assertThat(createdUser, equalTo(user));
        …
Seems perfect, but…
verify(em, times(1)).persist(user);


• Is brittle
• Violates DRY
• Is not a good use of a Mock
Implementations matter

TESTING WITH REAL OBJECTS
Using a real EntityManager
public class RealUserRepositoryTests {

   static EntityManagerFactory emf;
   EntityManager em;
   UserRepository userRepository;

   @BeforeClass public static void beforeClass() {
       emf = Persistence.createEntityManagerFactory("jpa-examples");
   }

   @Before public void setup() throws Exception {
       // Initialize a real EntityManager
       em = emf.createEntityManager();
       userRepository = new UserJPARepository(em);
       em.getTransaction().begin();
   }
   …
Testing with a real EntityManager
@Test
public void testCreateUser() throws Exception {
    // Setup
    User user = createTestUser();

    // Execute
    User createdUser = userRepository.create(user);
    em.flush();
    em.clear();

    // Verify
    User foundUser = em.find(User.class, createdUser.getUserId());
    assertThat(foundUser, equalTo(createdUser));
}
Better, but …
• Requires a separate persistence.xml
• Manual transaction management
• Flushes and clears the persistence context
  manually
Bringing the test as close as possible to production

ARQUILLIAN ENTERS THE SCENE
We must walk before we run
@RunWith(Arquillian.class)           // #1                                Use the Arquillian test
public class GreeterTest {                                                       runner.
    @Deployment                       // #2
    public static JavaArchive createDeployment() {                          Assemble a micro-
        return ShrinkWrap.create(JavaArchive.class)                            deployment
            .addClass(Greeter.class)
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }
                                                                               A CDI Bean.
    @Inject                          // #3                              Managed by the container.
    Greeter greeter;
                                                                         Injected by Arquillian.
    @Test                             // #4
    public void should_create_greeting() {
        assertEquals("Hello, Earthling!",                               Test like you normally do.
            greeter.greet("Earthling"));                                         No mocks.
    }                                                                       Just the real thing.
}
@RunWith(Arquillian.class)


   JUnit           TestNG
   >= 4.8.1         > 5.12.1
@Deployment
• Assemble test archives with ShrinkWrap
• Bundles the -
  – Class/component to test
  – Supporting classes
  – Configuration and resource files
  – Dependent libraries
Revisiting the deployment
      @Deployment                                                   // #1
      public static JavaArchive createDeployment() {
          return ShrinkWrap.create(JavaArchive.class)               // #2
              .addClass(Greeter.class)                              // #3
              .addAsManifestResource(EmptyAsset.INSTANCE,
     "beans.xml");                                                  // #4
      }

1.   Annotate the method with @Deployment
2.   Create a new JavaArchive. This will eventually create a JAR.
3.   Add our Class-Under-Test to the archive.
4.   Add an empty file named beans.xml to enable CDI.
Test enrichment
• Arquillian can enrich test class instances with
  dependencies.
• Supports:
   –   @EJB
   –   @Inject
   –   @Resource
   –   @PersistenceContext
   –   @PersistenceUnit
   –   @ArquillianResource
   –   …
Revisiting dependency injection
@Inject
Greeter greeter;



• The CDI BeanManager is used to create a
  new bean instance.
• Arquillian injects the bean into the test
  class instance, before running any tests.
Writing your tests
• Write assertions as you normally would
  – No record-replay-verify model
  – Assert as you typically do
  – Use real objects in your assertions
Running your tests
• Run the tests from your IDE or from your
  CI server
  – Just like you would run unit tests
     • Run as JUnit test - Alt+Shift+X, T
     • Run as Maven goal - Alt+Shift+X, M
Let’s recap
@RunWith(Arquillian.class)           // #1                                Use the Arquillian test
public class GreeterTest {                                                       runner.
    @Deployment                       // #2
    public static JavaArchive createDeployment() {                          Assemble a micro-
        return ShrinkWrap.create(JavaArchive.class)                            deployment
            .addClass(Greeter.class)
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }
                                                                               A CDI Bean.
    @Inject                          // #3                              Managed by the container.
    Greeter greeter;                                                     Injected by Arquillian.
    @Test                             // #4
    public void should_create_greeting() {
        assertEquals("Hello, Earthling!",
                                                                        Test like you normally do.
            greeter.greet("Earthling"));                                         No mocks.
    }                                                                       Just the real thing.
}
Using Arquillian to test the repository

TESTING THE REPOSITORY - DEMO
The stuff that Arquillian does under the hood

WHAT DID YOU JUST SEE?
Arquillian changes the way you see tests

WHY SHOULD YOU USE IT?
Refining the tests involving a database

THE PERSISTENCE EXTENSION
ATDD/BDD with Arquillian

THE DRONE AND JBEHAVE
EXTENSIONS
Arquillian : An introduction
Arquillian : An introduction
Arquillian : An introduction
Arquillian : An introduction

Arquillian : An introduction

  • 1.
    Arquillian : Anintroduction Testing with real objects Vineet Reynolds March 2012
  • 12.
    How does thissolve our problems? WHY ARQUILLIAN?
  • 13.
    Test Doubles redux Howdid we arrive at the current testing landscape?
  • 14.
    Let’s test arepository @Stateless @Local(UserRepository.class) public class UserJPARepository implements UserRepository { @PersistenceContext Injected by the container. private EntityManager em; How do we get one in our tests? public User create(User user) { em.persist(user); How do we test this? return user; } ... }
  • 15.
    Did you sayMocks? public class MockUserRepositoryTests { … @Before public void injectDependencies() { // Mock em = mock(EntityManager.class); userRepository = new UserJPARepository(em); } @Test public void testCreateUser() throws Exception { // Setup User user = createTestUser(); // Execute User createdUser = userRepository.create(user); // Verify verify(em, times(1)).persist(user); assertThat(createdUser, equalTo(user)); …
  • 16.
    Seems perfect, but… verify(em,times(1)).persist(user); • Is brittle • Violates DRY • Is not a good use of a Mock
  • 17.
  • 18.
    Using a realEntityManager public class RealUserRepositoryTests { static EntityManagerFactory emf; EntityManager em; UserRepository userRepository; @BeforeClass public static void beforeClass() { emf = Persistence.createEntityManagerFactory("jpa-examples"); } @Before public void setup() throws Exception { // Initialize a real EntityManager em = emf.createEntityManager(); userRepository = new UserJPARepository(em); em.getTransaction().begin(); } …
  • 19.
    Testing with areal EntityManager @Test public void testCreateUser() throws Exception { // Setup User user = createTestUser(); // Execute User createdUser = userRepository.create(user); em.flush(); em.clear(); // Verify User foundUser = em.find(User.class, createdUser.getUserId()); assertThat(foundUser, equalTo(createdUser)); }
  • 20.
    Better, but … •Requires a separate persistence.xml • Manual transaction management • Flushes and clears the persistence context manually
  • 21.
    Bringing the testas close as possible to production ARQUILLIAN ENTERS THE SCENE
  • 22.
    We must walkbefore we run @RunWith(Arquillian.class) // #1 Use the Arquillian test public class GreeterTest { runner. @Deployment // #2 public static JavaArchive createDeployment() { Assemble a micro- return ShrinkWrap.create(JavaArchive.class) deployment .addClass(Greeter.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } A CDI Bean. @Inject // #3 Managed by the container. Greeter greeter; Injected by Arquillian. @Test // #4 public void should_create_greeting() { assertEquals("Hello, Earthling!", Test like you normally do. greeter.greet("Earthling")); No mocks. } Just the real thing. }
  • 23.
    @RunWith(Arquillian.class) JUnit TestNG >= 4.8.1 > 5.12.1
  • 24.
    @Deployment • Assemble testarchives with ShrinkWrap • Bundles the - – Class/component to test – Supporting classes – Configuration and resource files – Dependent libraries
  • 25.
    Revisiting the deployment @Deployment // #1 public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) // #2 .addClass(Greeter.class) // #3 .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); // #4 } 1. Annotate the method with @Deployment 2. Create a new JavaArchive. This will eventually create a JAR. 3. Add our Class-Under-Test to the archive. 4. Add an empty file named beans.xml to enable CDI.
  • 26.
    Test enrichment • Arquilliancan enrich test class instances with dependencies. • Supports: – @EJB – @Inject – @Resource – @PersistenceContext – @PersistenceUnit – @ArquillianResource – …
  • 27.
    Revisiting dependency injection @Inject Greetergreeter; • The CDI BeanManager is used to create a new bean instance. • Arquillian injects the bean into the test class instance, before running any tests.
  • 28.
    Writing your tests •Write assertions as you normally would – No record-replay-verify model – Assert as you typically do – Use real objects in your assertions
  • 29.
    Running your tests •Run the tests from your IDE or from your CI server – Just like you would run unit tests • Run as JUnit test - Alt+Shift+X, T • Run as Maven goal - Alt+Shift+X, M
  • 30.
    Let’s recap @RunWith(Arquillian.class) // #1 Use the Arquillian test public class GreeterTest { runner. @Deployment // #2 public static JavaArchive createDeployment() { Assemble a micro- return ShrinkWrap.create(JavaArchive.class) deployment .addClass(Greeter.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } A CDI Bean. @Inject // #3 Managed by the container. Greeter greeter; Injected by Arquillian. @Test // #4 public void should_create_greeting() { assertEquals("Hello, Earthling!", Test like you normally do. greeter.greet("Earthling")); No mocks. } Just the real thing. }
  • 31.
    Using Arquillian totest the repository TESTING THE REPOSITORY - DEMO
  • 32.
    The stuff thatArquillian does under the hood WHAT DID YOU JUST SEE?
  • 40.
    Arquillian changes theway you see tests WHY SHOULD YOU USE IT?
  • 50.
    Refining the testsinvolving a database THE PERSISTENCE EXTENSION
  • 51.
    ATDD/BDD with Arquillian THEDRONE AND JBEHAVE EXTENSIONS