I agree that we need a better testing framework for Java EE / MP applications than what Arquillian currently offers. However, I think that improving on Arquillian would be the easiest path forward (until someone comes up with a proposal that warrants side-stepping Arquillian entirely). Personally, I hate needing to write up mock objects for testing, as it wastes valuable development time. I would much rather start up a real server and add a few seconds to the test runtime than to have to write extensive mocking code and worry that the mock objects behave differently than the real application will.
Of course, when testing a microservice architecture it isn't always feasible/possible to deploy all of the microservices during the test, so mocking interactions with other services will still be necessary.
I have extensive experience with testing Java EE applications (I do a lot of work on the custom test harness that Liberty uses), and I don't see starting up a real server with the real app as a big problem. Normally it takes <5 seconds to start a Liberty server with a basic test application, and then we can drive hundreds of live-server tests through that test application in a few seconds. No mock objects required.
I think the main issues with Arquillian are:
1) application packaging via ShrinkWrap is too tedious
SOLUTION: acknowledge that standard project layouts are a thing, and leverage that pattern to be able to build an app in 1 line of code (see ShrinkHelper.defaultApp() below)
2) arquillian does a lot of server stop/starts, which eats up much of the overall time a test suite takes
SOLUTION: reverse the antipattern of deploying lots of tiny test applications, and instead deploy the real application + some server-side testing classes (e.g. TestServletA below). This greatly simplifies/reduces the need to interact w/ Shrinkwrap and saves on overall test time.
3) setup is more complex that simply adding a dependency to your pom.xml
SOLUTION: App servers such as Liberty already have their own build plugins with default values for things like hostnames/ports/disk locations (which can be overridden). If there was some sort of glue between app server plugins and Arquillian, this could all be figured out automatically and there would be no need for an arquillian.xml, getting the simplicity level down to specifying pom dependencies.
To illustrate what we use in Liberty, our test-driver class is very basic, something like:
@RunWith(FATRunner.class)
public class SimpleTest {
public static final String APP_NAME = "app1";
@Server("FATServer")
@TestServlet(servlet = TestServletA.class, contextRoot = "APP_NAME")
public static LibertyServer server;
@BeforeClass
public static void setUp() throws Exception {
// assumes standard app layout for java and non-java resources.
// Only need to specify the server to deploy to, app name, and java packages to include
ShrinkHelper.defaultApp(server, APP_NAME, "com.app1.web.*");
server.startServer();
}
@AfterClass
public static void tearDown() throws Exception {
server.stopServer();
}
}
Then, all of the test code itself lives in TestServletA.java, which itself is a servlet annotated with regular JUnit @Test annotations, and can get real objects injected into it:
@WebServlet("/TestServletA")
public class TestServletA extends FATServlet {
@Inject
MyBean bean;
@Test
public void basicTest() throws Exception {
Assert.assertTrue(bean.doesSomething());
}
}
This isn't too far off from what the Spring test suite does already. If people are on board with this sort of approach, I'd be happy to contribute.
- Andy
IBM