2

I'm continuing my exploration of the Play framework and its related components. I used the template for CRUD application with a connection to a PostgreSQL database to begin with. It splits the application in models, repositories, controllers and views. This works well. Now, I'm trying to create some tests for this application with Specs2. More precisely, I'm trying to test the repository. It is defined as follow:

package dal
import javax.inject.{ Inject, Singleton }
import play.api.db.slick.DatabaseConfigProvider
import slick.driver.JdbcProfile

import models.Cat
import scala.concurrent.{ Future, ExecutionContext }

@Singleton
class CatRepository @Inject() (dbConfigProvider: DatabaseConfigProvider)(implicit ec: ExecutionContext) {
...
}

I would like to set an in memory database which would be created (schema, evolutions) before all tests, destroyed after all tests, populated (data, probably with direct SQL) and flushed around each test. I would like to pass it on to my repository instance which I would then use to perform my test. Like:

val repo = new CatRepository(inMem_DB)

So how do I go about: 1) creating this db and applying the evolutions? maybe:

trait TestDB extends BeforeAfterAll {
    var database: Option[Database] = None

    def before = {
        database = Some(Databases.inMemory(name = "test_db"))
        database match {
            case Some(con) => Evolutions.applyEvolutions(con)
            case _ => None
        }
        println("DB READY")
    }

    def after = {
        database match {
            case Some(con) => con.shutdown()
            case _ => None
        }
    }
}

Using a var and always making a "match/case" when I need to use the db isn't convenient. I guess there is a much better to do this...

2) Populate and flush around each test? Shall I create a trait extending Around, just as with BeforeAfterAll?

3) Create on of these play.api.db.slick.DatabaseConfigProvider from the database? Any link showing how to do this?

I found few examples which where covering this with running a FakeApplication, but I assume there is a way to pass somehow the db to such repository object outside of a running application..?

Thank you for helping. Cheers!

Xosted
  • 321
  • 2
  • 15

1 Answers1

0

You can use a lazy val and AfterAll for the database setup/teardown, then BeforeAfterEach for each example:

trait TestDB extends AfterAll with BeforeAfterEach {
  lazy val database: Database = 
    Databases.inMemory(name = "test_db")

  def afterAll = 
    database.shutdown


  def before = 
    database.populate

  def after =
    datbase.clean
}
Eric
  • 15,494
  • 38
  • 61
  • Thanks a lot @Eric, this helps for my first question. However, I'm still stuck with the two other questions. Actually, even when I try to use the FakeApplication facility, I still can't figure out how to populate the test database and pass it on to my repository for testing. – Xosted Dec 14 '15 at 15:14
  • That is the purpose of the `before` method. This method will be called before each test, so you can use it to populate your database. Then it is accessible because it is a `lazy val` visible to all the specification. However you need to use the `sequential` argument in your spec to make sure that each test stays isolated from another. – Eric Dec 14 '15 at 22:14
  • Yes, I wasn't clear in my last message. I do understand the role of before, after and afterAll here. The handle "database" allows for direct access to the db in memory and I should be able to apply the evolutions there too. My biggest issue comes from trying to pass on this database to the repository for testing. In production, the DatabaseConfigProvider is injected automatically. How do I replace/override/by pass this mechanism to provide the in memory db for testing? – Xosted Dec 15 '15 at 13:02
  • It looks like I'm completely out of track with this approach. Databases.inMemory doesn't seem to be compatible with using slick as db access layer. So here I am back to 0. I followed this: https://www.playframework.com/documentation/2.4.x/PlaySlick . I got 2 databases configured (default and test) and DatabaseConfig via Dependency Injection, just like indicated. How do I get to indicated which one to use for my tests? – Xosted Dec 15 '15 at 14:45
  • Maybe you can use Guice to inject exactly the test database you need: http://stackoverflow.com/questions/34159857/specs2-how-to-test-a-class-with-more-than-one-injected-dependency/34169760#34169760 – Eric Dec 15 '15 at 20:42
  • Hi @Eric, thank you for taking the time to help me with this. I am now looking at the link you provided and...it's scary. It seems to me like a rather huge amount of detour to achieve something common and usually quite simple. Besides I can now retrieve a repository (equivalent ReportService) ready to use, with it's dependencies already injected but, I still don't see how to specify which DB is to be "injected". The doc https://www.playframework.com/documentation/2.4.x/ScalaDependencyInjection indicates how to create various named bindings but I can't find how to set a specific one. – Xosted Dec 16 '15 at 08:50
  • Can you have a look at this test project: https://github.com/etorreborre/play-specs2-testbench. It is not using a real DB configuration but shows how to inject a test component using Guice. – Eric Dec 16 '15 at 10:53
  • I looked into it and tried to reproduce the same organization. Creating a trait with a method returning a DatabaseConfig and two implementations one for test, the other for production. But now, the problem is reversed. While it is clear how to indicate to the test which implementation to use (specification extends Inject), how do you set the implementation for production? Besides, when I try to run the test, a guice error is thrown because "No implementation for scala.concurrent.ExecutionContext was bound." (ExecutionContext is implicitly passed to the repository). – Xosted Dec 16 '15 at 15:32
  • Can you start a small github project based on those ideas and we collaborate from there? – Eric Dec 16 '15 at 21:41
  • Here is the project: https://github.com/Xosted/play-slick-specs2.git I simply cloned the Play Scala Intro project from here: https://typesafe.com/activator/template/play-scala-intro then I registered two databases in the application.conf. I added a test file for the repository then I implemented the changes suggested in the project you indicated and that is the status so far. Thank you for your time. – Xosted Dec 17 '15 at 12:42
  • Please see my [PR](https://github.com/Xosted/play-slick-specs2/pull/1). Still not completely working but I made some progress. – Eric Dec 17 '15 at 22:58
  • I think we are making some progress here. I could test that indeed, the correct database is used for the test and the other database for regular usage. However... something weird is occurring. – Xosted Dec 18 '15 at 18:38
  • I think we are making some progress here. I could test that indeed, the correct database is used for the test and the other database for regular usage. However... something weird is occurring. If I run the test by itself (meaning removing the tests that were delivered with the Play Scala Intro), everything is fine. But if they are all there, then this exception is thrown: "Execution exception[[IllegalStateException: Cannot initialize ExecutionContext; AsyncExecutor already shut down]]" So it seems that the application is getting closed somehow and can't be re-opened. – Xosted Dec 18 '15 at 18:52