Dependency Injection in Scala and Play! using the cake pattern

It is my first time using Scala and I wanted a simple way to do DI so I could unit test my controller easily. The ability to use traits really seems to have a positive impact on code design, and enables things like DI to be quite easy without a runtime framework.

Real work scala dependency injection was a great introduction to implementing the Cake pattern in Scala so I won’t repeat the specifics of it here.

In case you haven't come across it the Play! framework is a complete web framework for JVM languages.

Personally I did not want to override plays controller instantiation so things stayed simple and I kept a clean routes table.

# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

POST    /:topic/:key          controllers.Application.send(topic: String, key: String)
GET     /:topic/:key          controllers.Application.get(topic: String, key: String, groupId: String)

The standard play pattern changes slightly with the controller which is split between two definitions. The first is the Application object which works with the play route and inherites the ApplicationController trait. It defines a message consumer to a real implementation which is going to connect to a Kafka cluster and it is this that we will want to mock when running our unit tests.

object Application extends ApplicationController {
  val messageConsumer = new KafkaMessageConsumer
}

Now we have the ApplicationController itself which contains the controller behaviour and inherits from a MessageConsumerComponent which is where it has access to a message consumer. The controller does not care how this is created and just uses it.


trait ApplicationController extends Controller with MessageConsumerComponent {

  def get(topic: String, key: String, groupId: String) = Action {
    this.messageConsumer.get(topic, key, groupId)
    Ok("done")
  }

  def send(topic: String, key: String) = Action(parse.text) {
    request =>

      val body: String = request.body

      this.messageConsumer.send(topic, key, body)

      Ok("received: " + topic + ", " + key + "," + body)
  }
}

The message consumer is implemented as a pair of traits, the first as the interface which can be mocked and the second which is used in the cake pattern.

trait MessageConsumer {
  def get(topic: String, key: String, groupId: String)
  def send(topic: String, key: String, message: String)
}

trait MessageConsumerComponent {

  val messageConsumer: MessageConsumer

  class KafkaMessageConsumer extends MessageConsumer  {
    def get(topic: String, key: String, groupId: String) { ... }
    def send(topic: String, key: String, message: String) { ... }
  }
}

This MessageConsumerComponent defines a messageConsumer field which will be accessible by any classes which inherit from the trait and can be set to either the KafkaMessageConsumer or a mock object. That's all there is to this implementation, so let's take a look at how this is done in a unit test.

trait TestEnvironment extends MessageConsumerComponent with ApplicationController with Mockito
{
  val messageConsumer = mock[KafkaMessageConsumer]
}

@RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification with TestEnvironment {

  "getting by topic" should {

    "return list of messages" in {
      val result = this.get("topic","key","group")(FakeRequest())
      there was one(messageConsumer).get("topic", "key", "group")
      status(result) must beEqualTo(OK)
    }
  }
}

I've followed Jonas' example in using a TestEnvironment object, but to avoid creating an extra component for the Application my system under test is the TestEnvironment. It might be worth changing this later but to keep things simple I've chosen this way.

There were a further two implementations I came across which are here and here. You might prefer one of those implementations and they are worth a read.

I am new to Scala so if there are errors, design issues or a Scala faux pas please let me know!

@naeemkhedarun

NBehave: Some C# file templates

Here are a couple of templates that I use for getting started writing a new test fixture for C#-based NBehave tests.  Once you drop these into your templates folder (typically under My Documents in “Visual Studio 2010\Templates\ItemTemplates\Visual C#") then you will get the following when you add a new item:

nbehave templates

NBehaveMSTests.zip (1,021.00 bytes)

NBehaveNUnit.zip (992.00 bytes)

July 12 2010

Lost in the Delta Quadrant!

 

"A word to the wise is infuriating." 

Hunter S Thompson 

OK, for the three of you that read this I have been absent for a while due to never ending project pressures and futile attempts to buy a house at the moment (All things I had put off till after Agile 2009)

This post is (unfortunately) a bit on the short side, and really just an outline of some of the things I have in mind to write about in the coming months, as much to jog my memory as to, hopefully, keep you all interested,

Agile and UAT - Where this can come unstuck, how we can prevent it from doing just that

Behavior Driven Development and how we started implementing it (Given my project breaks, And I don't want it to, When I have better tests and they run, Then I am a happy bunny)

Stubborn QA Departments What do you do when you have a QA department that refuses to give you testers until the release phase of your project?

Where is the risk? Why is it when we contract agile we seem to expect our clients to take all the risk?

A bit of a brain dump on what I'm thinking at the moment. H opefully its enough to whet your appetite. among those topics I will probably be discussing some of the training material we generated while researching our talk for Agile 2009. Maybe I'll drop a bit of insight to what we are proposing for Agile 2010?

Or maybe I won't let that cat out of the bag - You'll have to wait and see.

Mal

 

Agile 2009 - We entered the water and got out alive

 

"It was the Law of the Sea, they said. Civilization ends at the waterline. Beyond that, we all enter the food chain, and not always right at the top."

Hunter S Thompson - The Great Shark Hunt 

Agile 2009 - Simon Bennett and I presented this talk and I have to say, it went down quite well. It could have gone horribly wrong after all.

When we proposed this session we had quite a few comments (All visible in the above link I think) that "the hate" we were talking about didn’t exist. So when we presented and asked the room to vote, Green if you didn’t feel the hate red if you did ....

 We got a LOT of red.

Which is just as well! If it had been all green we would have been letting people out early J

So - We see the hate, other people see it, Why is there so little information on it? The point of our talk was to investigate the reasons for this hate, see if there were clear reasons for it and see what the overall drivers were. This I think we achieved and I'll post some of the feedback here soon. Suffice to say what we got was quite positive.

We did get a few people turn up for a different session however - I believe they were looking for practical tools to make their testers (Or themselves) more agile. They wanted more direction which we didn’t give them but then that wasn’t the point of the presentation. And as Alistair Cockburn would say (Did say!) "That is a Shu question with a Ri answer"

I think it is probably a good topic for a whole other workshop (That I might consider for next year but hey, you will have to wait till next year to see if I do it)

The main thing I think we got from it is the environment your team and company creates for your testers has as much, if not more, impact on their ability to be agile than they themselves do. Treating people in a certain way in my experience will cause them to react in that manner.

Take teenagers, Where a shop decrees that all teenagers are shoplifters and a security guard must follow them around the teenagers will (In my opinion justifiably) think "Well - If you are going to treat me like a criminal anyway regardless if I steal or not then I may as well steal - You will treat me the same anyway"

If you don’t treat them all as criminals you will still get the odd thief (But you would have got that anyway) now though you won’t be actively encouraging the rest of them to behave that way

Your testers are no different! If you treat them as the last line of defence (Identified by the sentence "Why didn’t testing find this bug") they will take on a gatekeeper mentality

If you treat them as the sole people responsible for quality (Identified by the sentence "I’m finished it just needs to be tested now") then they will sit at the end and wait for you to throw the code over to them.

I could go on but basically I am saying until the environment permits your testers to be agile they simply can’t be, and many places won’t change the environment until the tester is agile.

So which really does come first? The chicken or the egg?

At the risk of sounding all Kanban and eastern mysticism ;-) you need to change both together, if that proves impossible change the environment first! You may have some short term testing difficulties while your testers attempt to maintain their to their old methods in an environment that  is hostile to those behaviours but then again. You cant drive a car on water, and it’s quite difficult to be non agile in an environment that is hostile to those behaviours.

I'm not saying this will work for everyone but I suspect that, as in nature, if the environment is hostile to behaviours you want to minimise then those behaviours should die out by a process of natural selection.

 

Older Posts