arquillian : an introduction
Post on 07-Nov-2014
3.223 Views
Preview:
DESCRIPTION
TRANSCRIPT
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
top related