Jonik Jonik - 1 year ago 194
Scala Question

Specs2: how to test a class with more than one injected dependency?

Play 2.4 app, using dependency injection for service classes.

I found that Specs2 chokes when a service class being tested has more than one injected dependency. It fails with "Can't find a constructor for class ..."

$ test-only services.ReportServiceSpec
[error] Can't find a constructor for class services.ReportService
[error] Error: Total 1, Failed 0, Errors 1, Passed 0
[error] Error during tests:
[error] services.ReportServiceSpec
[error] (test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 2 s, completed Dec 8, 2015 5:24:34 PM

Production code, stripped to bare minimum to reproduce this problem:

package services

import javax.inject.Inject

class ReportService @Inject()(userService: UserService, supportService: SupportService) {
// ...

class UserService {
// ...

class SupportService {
// ...

Test code:

package services

import javax.inject.Inject

import org.specs2.mutable.Specification

class ReportServiceSpec @Inject()(service: ReportService) extends Specification {

"ReportService" should {
"Work" in {
1 mustEqual 1


If I remove either
dependency from
, the test works. But obviously the dependencies are in the production code for a reason. Question is, how do I make this test work?

Edit: When trying to run the test inside IntelliJ IDEA, the same thing fails, but with different messages: "Test framework quit unexpectedly", "This looks like a specs2 exception..."; see full output with stacktrace. I opened a Specs2 issue as instructed in the output, though I have no idea if the problem is in Play or Specs2 or somewhere else.

My library dependencies below. (I tried specifying Specs2 version explicitly, but that didn't help. Looks like I need
specs2 % Test
as is, for Play's test classes like
to work.)

resolvers += "scalaz-bintray" at ""
libraryDependencies ++= Seq(
specs2 % Test,
"" %% "anorm" % "2.4.0",
"org.postgresql" % "postgresql" % "9.4-1205-jdbc42"

Answer Source

There is limited support for dependency injection in specs2, mostly for execution environments or command-line arguments.

There is nothing preventing you from just using a lazy val and your favourite injection framework:

class MySpec extends Specification with Inject {
  lazy val reportService = inject[ReportService]


With Play and Guice, you could have a test helper such as this:

import play.api.inject.guice.GuiceApplicationBuilder
import scala.reflect.ClassTag    

trait Inject {
  lazy val injector = (new GuiceApplicationBuilder).injector()

  def inject[T : ClassTag]: T = injector.instanceOf[T]
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download