Scala Play application does not start when capturing data sources from .conf application

I try to read in the data sources from my application.conf file, but every time I start my server or try to run test cases, I get a message that the application is not running.

Here is an example of what I'm trying to do:

Unit test, which is trying to read a property from my application.conf

 class DbConfigWebUnitTest extends PlaySpec with OneAppPerSuite { implicit override lazy val app: FakeApplication = FakeApplication( additionalConfiguration = Map("db.test.url" -> "jdbc:postgresql://localhost:5432/suredbitswebtest", "db.test.user" -> "postgres", "db.test.password" -> "postgres", "db.test.driver" -> "org.postgresql.Driver")) val dbManagementWeb = new DbManagementWeb with DbConfigWeb with DbTestQualifier "DbConfigWebTest" must { "have the same username as what is defined in application.conf" in { dbManagementWeb.username must be("postgres") } } } 

Here is my DbConfigWeb

 import play.api.Play.current trait DbConfigWeb extends DbConfig { qualifier: DbQualifier => val url: String = current.configuration.getString(qualifier + ".url").get val username: String = current.configuration.getString(qualifier + ".user").get val password: String = current.configuration.getString(qualifier + ".password").get val driver: String = current.configuration.getString(qualifier + ".driver").get override def database: DatabaseDef = JdbcBackend.Database.forURL(url, username, password, null, driver) override implicit val session = database createSession } trait DbQualifier { val qualifier: String } trait DbProductionQualifier extends DbQualifier { override val qualifier = "db.production" } trait DbTestQualifier extends DbQualifier { override val qualifier = "db.test" } 

and finally, here is my stack trace:

 [suredbits-web] $ last test:test [debug] Forking tests - parallelism = false [debug] Create a single-thread test executor [debug] Runner for sbt.FrameworkWrapper produced 0 initial tasks for 0 tests. [debug] Runner for org.scalatest.tools.Framework produced 2 initial tasks for 2 tests. [debug] Running TaskDef(com.suredbits.web.db.DbConfigWebUnitTest, sbt.ForkMain$SubclassFingerscan@48687c55 , false, [SuiteSelector]) [error] Uncaught exception when running com.suredbits.web.db.DbConfigWebUnitTest: java.lang.RuntimeException: There is no started application sbt.ForkMain$ForkError: There is no started application at scala.sys.package$.error(package.scala:27) at play.api.Play$$anonfun$current$1.apply(Play.scala:71) at play.api.Play$$anonfun$current$1.apply(Play.scala:71) at scala.Option.getOrElse(Option.scala:120) at play.api.Play$.current(Play.scala:71) at com.suredbits.web.db.DbConfigWeb$class.$init$(DbConfigWebProduction.scala:14) at com.suredbits.web.db.DbConfigWebUnitTest$$anon$1.<init>(DbConfigWebUnitTest.scala:14) at com.suredbits.web.db.DbConfigWebUnitTest.<init>(DbConfigWebUnitTest.scala:14) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:526) at java.lang.Class.newInstance(Class.java:379) at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:641) at sbt.ForkMain$Run$2.call(ForkMain.java:294) at sbt.ForkMain$Run$2.call(ForkMain.java:284) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) 
+5
source share
1 answer

I think the key problem is that val in Scala traits are initialized during the build that precedes the launch of the Play test application (presumably its life cycle is tied to each sample example). You have a couple of workarounds:

  • do everything in DbConfigWeb a def or maybe lazy val
  • give DbConfigWeb abstract field play.api.Application from which the configuration values ​​are extracted (not using current ) and pass it explicitly (fake application) to any DbManagementWeb as a constructor parameter

Here's a simplified version using the first approach (which works for me):

 import play.api.Play.current trait DbConfig trait DbConfigWeb extends DbConfig { self: DbQualifier => // Using defs instead of vals def url: String = current.configuration.getString(qualifier + ".url").get def username: String = current.configuration.getString(qualifier + ".user").get def password: String = current.configuration.getString(qualifier + ".password").get def driver: String = current.configuration.getString(qualifier + ".driver").get } trait DbQualifier { val qualifier: String } trait DbTestQualifier extends DbQualifier { override val qualifier = "db.test" } 

and spec:

 import controllers.{DbConfigWeb, DbTestQualifier} import org.scalatestplus.play.{OneAppPerSuite, PlaySpec} import play.api.test.FakeApplication class DbConfigTest extends PlaySpec with OneAppPerSuite { implicit override lazy val app: FakeApplication = FakeApplication( additionalConfiguration = Map("db.test.url" -> "jdbc:h2:mem:play", "db.test.user" -> "sa", "db.test.password" -> "", "db.test.driver" -> "org.h2.Driver")) val dbManagementWeb = new DbConfigWeb with DbTestQualifier "DbConfigWebTest" must { "have the same username as what is defined in application.conf" in { dbManagementWeb.username must be("sa") } } } 

Personally, I prefer the second approach, which saves the state of the application explicitly, rather than relying on play.api.Play.current , which you cannot rely on always running.

You mentioned in the comments that lazy val did not work for you, but I can only assume that some chain of calls made you initialize: check again that this is not so.

Please also note that the initialization order for val can be complicated, and although some may disagree, it is a pretty safe bet to stick with def as members of an element if you are not sure about its expensive operation (in this case lazy val may be an option.)

+10
source

Source: https://habr.com/ru/post/1212875/