Typesafe Activator

Play Framework using Scalatest for testing and SubCut for configuration

Play Framework using Scalatest for testing and SubCut for configuration

dickwall
Source
September 27, 2013
basics playframework subcut scalatest scala dependencyinjection

A sample play application with testing in Scalatest, and dependency configuration using SubCut which offers the ease of guice but with a completely Scala accent.

How to get "Play Framework using Scalatest for testing and SubCut for configuration" on your computer

There are several ways to get this template.

Option 1: Choose play-scalatest-subcut in the Typesafe Activator UI.

Already have Typesafe Activator (get it here)? Launch the UI then search for play-scalatest-subcut in the list of templates.

Option 2: Download the play-scalatest-subcut project as a zip archive

If you haven't installed Activator, you can get the code by downloading the template bundle for play-scalatest-subcut.

  1. Download the Template Bundle for "Play Framework using Scalatest for testing and SubCut for configuration"
  2. Extract the downloaded zip file to your system
  3. The bundle includes a small bootstrap script that can start Activator. To start Typesafe Activator's UI:

    In your File Explorer, navigate into the directory that the template was extracted to, right-click on the file named "activator.bat", then select "Open", and if prompted with a warning, click to continue:

    Or from a command line:

     C:\Users\typesafe\play-scalatest-subcut> activator ui 
    This will start Typesafe Activator and open this template in your browser.

Option 3: Create a play-scalatest-subcut project from the command line

If you have Typesafe Activator, use its command line mode to create a new project from this template. Type activator new PROJECTNAME play-scalatest-subcut on the command line.

Option 4: View the template source

The creator of this template maintains it at https://github.com/dickwall/activator-play-subcut#master.

Option 5: Preview the tutorial below

We've included the text of this template's tutorial below, but it may work better if you view it inside Activator on your computer. Activator tutorials are often designed to be interactive.

Preview the tutorial

Play with Dependency Injection and SubCut

Dependency injection is a design pattern that frees your code from creational concerns, making your code cleaner and easier to test.

This tutorial demonstrates dependency injection using SubCut and testing using Scalatest in a simple Play application. SubCut takes advantage of Scala's type system for dependency injection making it an easy, lightweight and type-safe way to inject your dependencies.

This tutorial will take about 10 minutes to complete and assumes that you are already familiar with the basics of a Play application.

Injecting the Application

First, take a look at the Application class. You should notice that a new parametric field has been added to the class, called bindingModule and of type BindingModule, it is also marked as implicit which means the Scala compiler can automatically fill it in if a BindingModule type is required by some other method or new class instance.

The class has also had the Injectable trait added to it, this allows configured bound instances to be automatically injected upon creation of a new instance of the class. The line

val textGenerator = inject[TextGenerator]
achieves this, but you can already make an improvement to this code. This form of injection will fail if no TextInjector has been configured in the bindings you are using, but if you change the injection to:
injectOptional[TextGenerator] getOrElse new WelcomeTextGenerator
instead, then SubCut will use the configured TextGenerator if bound, or fall back on the default WelcomeTextGenerator if not.

This is safer at runtime and also makes it easy to see what the "standard" definition for the TextGenerator is in normal usage, rather than having to dig through configuration files to see what is used in the typical case.

TextGenerator

TextGenerator is an abstract class and we have a concrete implementation of it in the form of WelcomeTextGenerator which is our standard implementation.

TextGenerator is a rudimentary service that simply generates text. You'll have more useful services in your code e.g. a repository service that is backed by a concrete class to communicate with a database. By using dependency injection we can configure the type of service required outside of the class that needs to call on it.

To make things a little bit more interesting, we have an embedded dependency inside of WelcomeTextGenerator called welcomeText of type Greeting. This requires WelcomeTextGenerator to also be injectable, which means it also needs the implicit bindingModule defined. Then the Greeting instance configured is injected as well. This injection already uses the safer injectOptional form so that if a configured binding cannot be found at runtime, it will use the default instead. It then gets the value from inside that Greeting as the String to welcome people to the site.

Bindings and Configuration

The configuration for the injected items is defined in the StandardBindings object which extends NewBindingModule. Within the constructor code (which is actually a function of MutableBindingModule to Unit), bindings are made using a simple DSL. When the function has been used by the constructor the Mutability is removed, so the resulting BindingModule is immutable (and thread safe).

The line import module._ makes it more convenient to make the bindings as you are able to say bind [Type] ... instead of module.bind [Type] ....

The first binding provides a single instance that will always be used when a Greeting is required. Greeting is a simple leaf class (i.e. not injected itself) so we just make a new Greeting and bind it to the Greeting type. Note that it is perfectly valid to bind a type to an instance of the same type, it does not have to be a subtype (so you can bind any instance of a class to the type of that class if it makes sense).

The second binding is for TextGenerator and provides a WelcomeTextGenerator instance. WelcomeTextGenerator is itself injected, so we need to carry the binding module through to it as well. Because modules can be updated (they are immutable, but can be copied and updated to new bindings in the copying resulting in a new immutable binding module but with a different configuration) we use the toModuleSingle binding, which makes the current module (whatever it is) available to the class you are creating. It is marked implicit so that the call to new will pick up the binding module automatically, but you could also remove the implicit module and use placeholder syntax to pass the module through to the new instance explicitly. Give it a go by replacing that binding line with the following code:

bind [TextGenerator] toModuleSingle { new WelcomeTextGenerator()(_) }
and save the file to test that everything still works.

Testing with SubCut and ScalaTest

Now take a look at ApplicationTest. In this test, we are going to use a mock to verify that a request for the welcome page to the Application does invoke the welcomeText method on the TextGenerator. In order to do this we create a mock TextGenerator instance and then bind it in for the TextGenerator for the purposes of the test.

StandardBindings.modifyBindings { implicit module => takes the StandardBindings we have for the project and provides you with a copy of the bindings that you can modify. This lets you re-bind some of the types to provide alternative implementations than the standard ones. In this case we bind the mocked textGenerator instance in for TextGenerator so that it will use our mock instead.

Creating the Application instance with new now uses our modified test bindings, and when we make a fake page request, it calls through to the TextGenerator which uses the mock. At the end of the test we verify that welcomeText was called in the mock.

Modifying SubCut bindings in tests is completely thread-safe, each modification gets its own copy of the bindings so they do not interfere with one another. This means all tests can be run in parallel, mocking out different parts of the system or just re-configuring bindings for that test, and it will not affect any of the other tests running at the same time.

Integrating with Play

The final part to using SubCut with Play is to integrate the injection into the play lifecycle. Since the Application class is now injected and takes a bindingModule as a constructor parameter we will need to provide that bindingModule when play gets a new Controller instance (e.g. Application).

Look at Global to see how this is accomplished. The standard implementation of GlobalSettings in play uses reflection to create an instance of a new controller class, but only works if the Controller has a default (no-parameter) constructor. We need to override the implementation of the getControllerInstance method and add the ability to fill in the StandardBindings.

The least invasive way to do this is to attempt to create the instance with the default constructor first (some of our controllers may not be injected and will still have a default constructor) and if that fails, try and use the constructor that takes a BindingModule instead. This is what the code you see here does - if the newInstance for a default constructor fails with a ReflectionException then try and look up the BindingModule constructor - if it is there we can use it, and if not we get the same kind of ReflectionException we would have got before.

Once we have the constructor we can pass in the StandardBindings (which will be the configuration we use for production) to the new instance. This is then implicitly passed down to all children of that class if needed, and to their children, and so on. This is the Scala feature that SubCut uses to pass the configuration down to any class that needs it - you just have to make sure that there is an unbroken chain of the implicit BindingModule parameter down to the classes that need them, and the Scala compiler helps with that.

1,1 Top
comments powered by Disqus