The Play team has been hard at work on Play 2.4 for almost a year now. With a release scheduled for Q2, we’re coming to the final stages, about to release the last milestone, and looking toward the RC phase of the project. The headline feature ofPlay 2.4 is dependency injection support from the core. This is part of a larger plan to eventually remove Play’s reliance on global state (the “current” application), allowing more flexible deployment and simpler testing of Play applications.
When it comes to dependency injection, there are many different competing opinions about how it should be done and what it should look like. In the Java world, the debate tends to be between which dependency injection framework to use, the main players being Spring and Guice, plus a few other candidates such as Dagger and JEE CDI, each offering their own advantages and slightly different perspectives. In the Scala world, the debate tends to be about whether you need a dependency injection framework or not, and if not, what Scala language features you can or should exploit to achieve dependency injection without a framework.
Our approach to DI on Play has therefore been to be unopinionated at the core, allowing any DI approach or framework to be used, while providing great support for one DI framework out of the box, and great support for one Scala compile time dependency injection approach out of the box. The DI framework that we’ve chosen is Guice, due to its popularity and simplicity, and for compile time dependency injection we’ve provided some traits that implement a “lightweight cake pattern”. Other DI frameworks and patterns we expect to be provided by the Playcommunity. You can read about using Guice with Play 2.4 in Java and Scala, and also about using compile time dependency injection in Scala.
While supporting DI in the core of Play is an interesting new feature in itself, the main advantage that it brings is not realised until you start writing tests. This we believe is where Play 2.4 brings some of its most interesting new features to the table, and it’s what we’ve spent the past few months focussing on.
Of course, once you’re using DI, unit testing becomes a lot easier, and there’s nothing much that Play needs to provide to help this - existing tools such as Mockito for providing mocked implementations of components are more than capable of helping to realise some of the advantages of using dependency injection.
However, once you move onto integration testing, this is where Play can start to realise the advantages of DI. The first thing we’ve focussed on here is being able to instantiate common Play components outside of a running application. For example,Play’s database and evolution support can now be easily used independently ofPlay, making it straight forward to write unit tests to test your database access code, including SQL queries. You can see how to do this in Java and Scala.
Play also now makes it very simple to create embedded servers in Java and Scala using a simple Java routing DSL and a Scala string interpolating routing DSL, and this makes it very straight forward to test web service client code in Java and Scala.
We’ve also put a lot of work into full application functional testing helpers, replacing the old FakeApplication that Play provides with new Guice application builders inJava and Scala. These builders are far more flexible, allowing any arbitrary component to be overridden, and allowing entire modules to be enabled or disabled.
Having convenient test APIs we believe is crucial to enabling developers to write comprehensive high value tests, which in turn increases the quality of the software developers write. For this reason, we’re most excited about the new test APIs inPlay 2.4, and we hope you’ll enjoy them too.