Play Slick: How to inject DbConfigProvider in tests
Asked Answered
S

1

6

I am using Play 2.5.10, Play-slick 2.0.2, and my activator-generated project comes with scalatest and code like this:

class TestSpec extends PlaySpec with OneAppPerSuite {...}

I managed to test routes/Actions; now I would test DAO methods on a lower level. I searched the web and SO for a solution, and could not find any that is still up-to-date. A DAO signature is like this:

class TestDAO @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends HasDatabaseConfigProvider[JdbcProfile]

so I need to pass it the dbConfigProvider thing. For some reason I can't inject the provider into the tests like we do in controllers (no error, tests just won't run):

class TestSpec @Inject()(dbConfigProvider: DatabaseConfigProvider) extends PlaySpec with OneAppPerSuite {...}

The Play-Slick docs say we can alternatively use a global lookup

val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)

but it won't work directly because

There is no started application

and link to an example project doing that:

class TestDAOSpec extends Specification {
  "TestDAO" should {
    "work as expected" in new WithApplicationLoader {   // implicit 'app'
      val app2dao = Application.instanceCache[TestDAO].apply(app)

but I could never find the WithApplicationLoader. Instead, there seems to be a WithApplication:

class TestDAOSpec extends Specification {
  "TestDAO" should {
    "work as expected" in new WithApplication() {   // implicit 'app'
      val app2dao = Application.instanceCache[TestDAO].apply(app)

but then I get

Type mismatch: expected a play.api.Application, got: play.Application.

At this point I lost hope.

How can I test a DAO?

N.B. I don't need to switch databases for testing (I handle this via config), I just want to access the default database in tests.

Sporophore answered 3/2, 2017 at 9:33 Comment(3)
You just need an application in scope, so mix in a OneAppPerSuite or OneAppPerTest. See here.Dactylo
I do with OneAppPerSuite, yet I get this. One solution I found was to import play.api.Play.current in the WithApplication() version, then it works but I get a deprecation warning.Sporophore
It worked with that example, thanks a lot. I overrid PlaySpec to include all that mysterious mess. I am totally disgusted by how this is so incredibly complicated. Override the implicit app that comes from nowhere, GuiceApplicationBuilder, repeat the conf you already have in your config for no apparent reason, instanceCache, whaaat?? And if I can copy and paste that after sooo many hours trying everything else, why is that not already in the framework???Sporophore
I
3

You can use:

lazy val appBuilder: GuiceApplicationBuilder = new GuiceApplicationBuilder().in(Mode.Test) 
lazy val injector: Injector = appBuilder.injector()
lazy val dbConfProvider: DatabaseConfigProvider = injector.instanceOf[DatabaseConfigProvider]
Iinde answered 22/2, 2017 at 13:28 Comment(2)
It works and answers the question directly. For other viewers, this is to be inserted into an extension of PlaySpec like in this example github.com/sake92/PlayGuiceExample/blob/master/test/dao/…. DatabaseConfigProvider.get[JdbcProfile](app) also works now that I know how to obtain my implicit app. But these few lines made me understand a lot of things, thanks.Sporophore
It needs to run the play application, and we have to mock lots of things! What happened if we need to initiate and test only the repository layer?Legault

© 2022 - 2024 — McMap. All rights reserved.