Arquillian : An introduction

Preview:

DESCRIPTION

Testing with real objects

Citation preview

Arquillian : An introduction

Testing with real objects Vineet Reynolds

March 2012

WHY ARQUILLIAN? How does this solve our problems?

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

private EntityManager em;

public User create(User user) {

em.persist(user);

return user;

}

...

}

Injected by the container. How do we get one in our

tests?

How do we test this?

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

TESTING WITH REAL OBJECTS Implementations matter

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

ARQUILLIAN ENTERS THE SCENE Bringing the test as close as possible to production

We must walk before we run @RunWith(Arquillian.class) // #1

public class GreeterTest {

@Deployment // #2

public static JavaArchive createDeployment() {

return ShrinkWrap.create(JavaArchive.class)

.addClass(Greeter.class)

.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");

}

@Inject // #3

Greeter greeter;

@Test // #4

public void should_create_greeting() {

assertEquals("Hello, Earthling!",

greeter.greet("Earthling"));

}

}

Use the Arquillian test runner.

Assemble a micro-deployment

A CDI Bean. Managed by the container.

Injected by Arquillian.

Test like you normally do. No mocks.

Just the real thing.

@RunWith(Arquillian.class)

JUnit >= 4.8.1

TestNG > 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

public class GreeterTest {

@Deployment // #2

public static JavaArchive createDeployment() {

return ShrinkWrap.create(JavaArchive.class)

.addClass(Greeter.class)

.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");

}

@Inject // #3

Greeter greeter;

@Test // #4

public void should_create_greeting() {

assertEquals("Hello, Earthling!",

greeter.greet("Earthling"));

}

}

Use the Arquillian test runner.

Assemble a micro-deployment

A CDI Bean. Managed by the container.

Injected by Arquillian.

Test like you normally do. No mocks.

Just the real thing.

TESTING THE REPOSITORY - DEMO

Using Arquillian to test the repository

WHAT DID YOU JUST SEE? The stuff that Arquillian does under the hood

WHY SHOULD YOU USE IT? Arquillian changes the way you see tests

THE PERSISTENCE EXTENSION Refining the tests involving a database

THE DRONE AND JBEHAVE EXTENSIONS

ATDD/BDD with Arquillian

Recommended