Arquillian and PowerMock: In-container testing with PowerMock

Testing in-container applications that use EJB, CDI or other injection dependency frameworks while using PowerMock at the same time turns out to be really hard.

TestNG

Using the combination of Arquillian and PowerMock in TestNG is actually not possible at all for the following reason: According to the official PowerMock documentation[1] TestNG must be configured with the following two steps to use PowerMock. Firstly, the TestNG suite.xml must be configured to use the PowerMockObjectFactory.

<suite name="dgf" verbose="10" object-factory="org.powermock.modules.testng.PowerMockObjectFactory">  
    <test name="dgf">
        <classes>
            <class name="com.mycompany.Test1"/>
            <class name="com.mycompany.Test2"/>
        </classes>
    </test>
</suite>  

Secondly, the test class itself must inherit from the PowerMockTestCase class.

Furthermore, the Arquillian documentation[2] requires the test class to inherit from the Arquillian class which is where our TestNG hopes die.

JUnit

At first glance things look rough here too because the aforementioned docs for JUnit require us to annotate or test class to run with both runners. On the one hand we have to configure the PowerMockRunner like this:

@RunWith(PowerMockRunner.class)
public class YourTestCase {  
    @Test
    public void test() {
        // ...
    }
}

And on the other hand we should configure the Arquillian runner:

@RunWith(Arquillian.class)
public class YourTestCase {  
    @Test
    public void test() {
        // ...
    }
}

Obviously only one runner can be configured at the same time.

PowerMock however has introduced a method to bootstrap itself using a JUnit rule[3] thus avoiding the JUnit TestRunner dilemma:

@RunWith(Arquillian.class)
public class YourTestCase {

    @Rule
    PowerMockRule rule = new PowerMockRule();

    @Test
    public void test() {
        // ...
    }
}

Apparently this is the way to go if you are using JUnit. However, even in the newest versions of PowerMock (1.5.4) this bootstrapping method seems to be working only barely. I've had trouble mocking static final classes regardless of this configuration.

Closing Thoughts

In-container testing is always integration testing and not unit testing! The injections you allow Arquillian to make always require the other units you inject to work correctly!

Consider separating your in-container-/integration-tests and out-of-container/unit-tests. Both are equally important but serve different purposes.

The latter requires no container-testing framework like Arquillian. Consider the following CDI bean:

import javax.inject.Inject;  
...

@Named
@RequestScoped
public class UserProcessor {

    @Inject
    private UserService userService;

    ...
}

Unit-Testing this with PowerMock can be done easily in the following manner:

public class UserProcessorTest extends PowerMockTestCase {

    private UserProcessor userProcessor;

    // spy(new UserService()) for a partial mock
    private UserService userService = mock(UserService.class);

    @BeforeMethod
    public void initMocks() {
        userProcessor = new UserProcessor();
        Whitebox.setInternalState(userProcessor, "userService", userService);
    }

    @Test
    public void testUserService() {
        // ...
    }
}

Finally, a new in-container contestant is on the rise: Apache DeltaSpike[4]. The Apache OpenWebBeans documentation[5] outlines how to use it for in-container testing. I couldn't get it to work with CDI though :(

1. https://code.google.com/p/powermock/wiki/TestNG_usage
2. http://docs.jboss.org/arquillian/reference/1.0.0.Alpha1/en-US/html_single/#d0e429
3. https://code.google.com/p/powermock/wiki/PowerMockRule
4. http://deltaspike.apache.org/
5. http://openwebbeans.apache.org/testing_cdictrl.html

Lukas

Read more posts by this author.

Dortmund, Germany https://lukaspradel.com

Subscribe to Programming & Whisky

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!