Search code examples
scalaplayframeworkimplicitspecs2

Scala / specs2 : could not find implicit value for evidence parameter of type AsExecution[ExecutionEnv => MatchResult[Future[AuthenticationResult]]]


I am trying to upgrade a Scala/Play application to Play 2.7, Scala 2.12.11.

I have the following test that probably used to work before I upgraded Play and Scala.

After the upgrade, I got the following compilation error:

Error: could not find implicit value for evidence parameter of type org.specs2.specification.core.AsExecution[org.specs2.concurrent.ExecutionEnv => org.specs2.matcher.MatchResult[scala.concurrent.Future[services.AuthenticationResult]]]

import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable.Specification

import scala.concurrent.duration._

class AuthenticationServiceSpec extends Specification {

  "The AuthenticationService" should {

    val service: AuthenticationService = new MyAuthenticationService

    "correctly authenticate Me" in { implicit ee: ExecutionEnv =>
      service.authenticateUser("myname", "mypassowrd") must beEqualTo (AuthenticationSuccessful).await(1, 200.millis)
    }

  }

}

To try to solve the compilation error, I added an implicit parameter to the class constructor (BTW, how did it work before, without an implicit parameter?):

import org.specs2.concurrent.ExecutionEnv
import org.specs2.mutable.Specification

import scala.concurrent.duration._
import scala.concurrent.Future

import org.specs2.specification.core.AsExecution
import org.specs2.matcher.MatchResult    

class AuthenticationServiceSpec(implicit ee: AsExecution[ExecutionEnv => MatchResult[Future[AuthenticationResult]]]) extends Specification {

  "The AuthenticationService" should {

    val service: AuthenticationService = new MyAuthenticationService

    "correctly authenticate Me" in { implicit ee: ExecutionEnv =>
      service.authenticateUser("myname", "mypassowrd") must beEqualTo (AuthenticationSuccessful).await(1, 200.millis)
    }

  }

}

However in runtime when I run the test, I am getting the error:

Can't find a suitable constructor with 0 or 1 parameter for class org.specs2.specification.core.AsExecution

Based on the constructor of AsExecution, it makes sense...

How can I solve this problem then?


Solution

  • This should work

    class AuthenticationServiceSpec(implicit ee: ExecutionEnv) extends Specification {
    
      "The AuthenticationService" should {
    
        val service: AuthenticationService = new MyAuthenticationService
    
        "correctly authenticate Me" in {
          service.authenticateUser("myname", "mypassword") must beEqualTo (AuthenticationSuccessful).await(1, 200.millis)
        }
    
      }
    
    }
    

    The ee: ExecutionEnv will be injected directly in the specification when it is built.

    That's the meaning of the message Can't find a suitable constructor with 0 or 1 parameter for class .... specs2 tries to recursively build arguments for a specification if they have a constructor with 0 or 1 argument. The ExecutionEnv is such an argument that specs2 is able to build on its own.