How to manually create a class with a configuration for testing - scala

I have a class that I use in playframework that automatically injects the dependency.
How can I create this class "manually" in my test code:
class AppConfog #Inject()(c: Configuration) {
val supportEmail = c.getString("app.email").get
...
}
I'm not sure how to get a Configuration class to pass into it.
I know I can create an inline config like:
val config =
"""
akka {
loglevel = "WARNING"
}
"""
ConfigFactory.parseString(config)
How do I get a Configuration from a config?

I think that Play's Configuration just wraps Typesafe Config that you get with your ConfigFactory.parseString(config). See here.
So you should be able to do this:
val underlying = ConfigFactory.parseString(config)
val configuration = Configuration(underlying)
val mockAppConfog = new AppConfog(configuration)

Related

Reactivemongo parseURI is failing when loading from config saying it can't find implicit value for parameter loader MongoConnection.ParsedURI

I am trying to use the reactivemongo driver in my play application without using the play module for reactive mongo.
So when I try and get the parsedURI from my config, I am getting the below error:
import reactivemongo.api.MongoConnection.ParsedURI
import reactivemongo.api.AsyncDriver
import com.typesafe.config.Config
val driver = new AsyncDriver(Some(config.get[Config]("mongodb")))
val parsedUri = config.get[ParsedURI]("mongodb.uri")
Error message:
could not find implicit value for parameter loader:
play.api.ConfigLoader[reactivemongo.api.MongoConnection.ParsedURI]
[error] val parsedUri = config.getParsedURI
[error] ^ [error] one error
found
My application.conf has:
mongodb {
uri = "mongodb://127.0.0.1:27017/mydb"
mongo-async-driver = ${akka}
}
ConfigLoader is a Play type class (like Reads) which tells play how to read a type from the config file.
You can find an explanation here: https://www.playframework.com/documentation/2.8.x/ScalaConfig#ConfigLoader
Generally you would define this by doing something like:
// Config
{
config {
url = "https://example.com"
}
}
// Config class
case class AConfig(url: String)
// Config Loader
implicit val configLoader: ConfigLoader[AConfig] = ConfigLoader {root => key =>
val config = root.getConfig(key)
AConfig(config.get[String]("url"))
}
// Usage
val aConfig = config.get[AConfig]("config")
In this case I would not suggest attempting to make one for ParsedURI because it is quite a complex type. Instead I would suggest doing something like:
val parsedUri: Try[ParsedURI] = MongoConnection.parseURI(config.get[String]("mongodb.uri"))

In Scaldi, I loaded my own typesafe config, how can I set Scaldi to make it available?

I want to load my own config from a configuration file. After loading the config I want to be able to inject the config values using Scaldi. Here is the code where I load the typesafe config. How can I adjust this code so that I can use this module and inject like: val localValue = inject [String] ("property.name")
package somepackage
import java.io.File
import com.typesafe.config.ConfigFactory
import scaldi._
class GlobalModule extends Module {
privateLoadConfig()
private def privateLoadConfig() = {
val c = System.getProperty("jumpmicro.config.path")
val configPath = if (c == null) "jumpmicro.conf" else c
if (configPath != null) {
val f = new File(configPath)
if (f.exists()) {
val config = ConfigFactory.parseFile(f)
// #todo What to do here?
}
}
}
}
The following should work for you:
implicit val inj = TypesafeConfigInjector(ConfigPath) // or config, both work
val localValue = inject [String] ("property.name")
Otherwise you can just append TypesafeConfigInjector(ConfigPath) to your module definition using :: operator (http://scaldi.org/learn/#injector-composition)

How to test actors with components injected by Guice in Play! scala 2.5

I'm using Guice to inject components inside an actor as it is explained in the Play! Scala 2.5 documentation.
In my application, I inject unshortLinksFactory: UnshortLinks.Factory in my classes and I create a new actor like this:
val unshortLinksActor = actorSystem.actorOf(Props(unshortLinksFactory(ws)))
The problem is that I cannot inject components in my test class (can I?) otherwise the test are not started. (Please note that I use Scalatest.)
How can I create the actor in my tests? It's fine if I can create it like:
val unshortLinksActor = system.actorOf(Props(unshortLinksFactory(ws)))
but the best would be to be able to create it with TestActorRef from Akka.testKit in order to have access to the underlyingActor.
What I do in order to test it is:
I extends the test class with TestKit(ActorSystem("testSystem")).
Then I create the Props like this:
lazy val unshortLinkFactoryProps = Props(unshortLinkFactory(
dbConfigProvider = dbConfProvider)
Here dbConfProvider is created like this but could also be mocked:
lazy val appBuilder = new GuiceApplicationBuilder()
lazy val injector = appBuilder.injector()
lazy val dbConfProvider = injector.instanceOf[DatabaseConfigProvider]
Finally I can have an actorRef like this:
val actorRef = TestActorRef[UnshortLinksActor](unshortLinksFactoryProps)
And I can access the methods inside my actor with actorRef.underlyingActor.

Testing Play + Slick app

I've a simple CRUD app built with Scala Play 2.4.3 and Play-slick 1.1.0 (slick 3.1.0) that uses a MySQL database for persistent storage.
I was trying to create the tests for my app and I saw 2 main options:
mocking database access, that as far as I've seen, requires some code changes
make tests use an alternative database (probably, in memory H2).
What's the best approach (vantages and desavantages)?
I prefer the second approach, but I'm finding some difficulties in setting up the tests.
What do I need to do? First, I think that I need to do the tests run with a FakeApplication, right? Do I need any sbt dependency to be able to do that?
After that, how do I specify to use the H2 database?
I had the same struggle and I came up with a solution like this(using second approach):
Create a context for DAO to use:
trait BaseContext{
def dbName: String
val dbConfig = DatabaseConfigProvider.get[JdbcProfile](dbName)
val db = dbConfig.db
val profile = dbConfig.driver
val tables = new Tables { // this is generated by Schema Code Generator
override val profile: JdbcProfile = dbConfig.driver
}
}
#Singleton
class AppContext extends BaseContext{
def dbName = "mysql" // name in your conf right after "slick.dbs"
}
#Singleton
class TestingContext extends BaseContext{
def dbName = "h2"
}
Then create a module to bind the injection, and don't forget to enable it in conf using play.modules.enabled += "your.Module":
class ContextModule(environment: Environment, configuration: Configuration) extends AbstractModule {
override def configure(): Unit = {
if (configuration.getString("app.mode").contains("test")) {
bind(classOf[BaseContext])
.to(classOf[TestingContext])
} else {
bind(classOf[BaseContext])
.to(classOf[AppContext])
}
}
}
And inject it to every DAO you've created:
class SomeDAO #Inject()(context: BaseContext){
val dbConfig = context.dbConfig
val db = context.db
val tables = context.tables
import tables.profile.api._
def otherStuff....
// you can call db.run(...), tables.WhateverYourTableIs, tables.TableRowCaseClass, ...
}
And final step, your configuration file. In my case I used app.mode to mark the environment, and I use separate .conf for different environment. Of cause, in these conf you must have the correct DB configuration. Here's the sample:
app.mode = "test"
# Database configuration
slick.dbs = {
# for unit test
h2 {
driver = "slick.driver.H2Driver$"
db = {
url = "jdbc:h2:mem:test;MODE=MYSQL"
driver = "org.h2.Driver"
keepAliveConnection = true
}
}
}
I'm pretty sure my solution is not a elegant one, but it deliver the goods. :)
Any better solution is welcomed!
my solution was to add step(Play.start(fakeApp)) in the beginning of each spec, and step(Play.stop(fakeApp)) in the end of each spec.
Also:
def fakeApp: FakeApplication = {
FakeApplication(additionalConfiguration =
Map(
"slick.dbs.default.driver" -> "slick.driver.H2Driver$",
"slick.dbs.default.db.driver" -> "org.h2.Driver",
"slick.dbs.default.db.url" -> "jdbc:h2:mem:play"
))
}
This was needed because I'm using play-slick, which requires configurations like:
slick.dbs.default.driver = "slick.driver.MySQLDriver$"
slick.dbs.default.db.driver = "com.mysql.jdbc.Driver"
slick.dbs.default.db.url = "jdbc:mysql://localhost/database"
slick.dbs.default.db.user = "user"
slick.dbs.default.db.password = "password"
more info on the docs

How to apply manually evolutions in tests with Slick and Play! 2.4

I would like to manually run my evolution script at the beginning of each test file. I'm working with Play! 2.4 and Slick 3.
According to the documentation, the way to go seems to be:
Evolutions.applyEvolutions(database)
but I don't manage to get an instance of my database. In the documentation play.api.db.Databases is imported in order to get a database instance but if I try to import it, I get this error: object Databases is not a member of package play.api.db
How can I get an instance of my database in order to run the evolution script?
Edit: as asked in the comments, here is the entire source code giving the error:
import models._
import org.scalatest.concurrent.ScalaFutures._
import org.scalatest.time.{Seconds, Span}
import org.scalatestplus.play._
import play.api.db.evolutions.Evolutions
import play.api.db.Databases
class TestAddressModel extends PlaySpec with OneAppPerSuite {
lazy val appBuilder = new GuiceApplicationBuilder()
lazy val injector = appBuilder.injector()
lazy val dbConfProvider = injector.instanceOf[DatabaseConfigProvider]
def beforeAll() = {
//val database: Database = ???
//Evolutions.applyEvolutions(database)
}
"test" must {
"test" in { }
}
}
I finally found this solution. I inject with Guice:
lazy val appBuilder = new GuiceApplicationBuilder()
lazy val injector = appBuilder.injector()
lazy val databaseApi = injector.instanceOf[DBApi] //here is the important line
(You have to import play.api.db.DBApi.)
And in my tests, I simply do the following (actually I use an other database for my tests):
override def beforeAll() = {
Evolutions.applyEvolutions(databaseApi.database("default"))
}
override def afterAll() = {
Evolutions.cleanupEvolutions(databaseApi.database("default"))
}
Considering that you are using Play 2.4, where evolutions were moved into a separate module, you have to add evolutions to your project dependencies.
libraryDependencies += evolutions
Source: Evolutions
Relevant commit: Split play-jdbc into three different modules
To have access to play.api.db.Databases, you must add jdbc to your dependencies :
libraryDependencies += jdbc
Hope it helps some people passing here.
EDIT: the code would then look like this :
import play.api.db.Databases
val database = Databases(
driver = "com.mysql.jdbc.Driver",
url = "jdbc:mysql://localhost/test",
name = "mydatabase",
config = Map(
"user" -> "test",
"password" -> "secret"
)
)
You now have an instance of the DB, and can execute queries on it :
val statement = database.getConnection().createStatement()
val resultSet = statement.executeQuery("some_sql_query")
You can see more from the docs
EDIT: typo
I find the easiest way to run tests with evolutions applied is to use FakeApplication, and input the connection info for the DB manually.
def withDB[T](code: => T): T =
// Create application to run database evolutions
running(FakeApplication(additionalConfiguration = Map(
"db.default.driver" -> "<my-driver-class>",
"db.default.url" -> "<my-db-url>",
"db.default.user" -> "<my-db>",
"db.default.password" -> "<my-password>",
"evolutionplugin" -> "enabled"
))) {
// Start a db session
withSession(code)
}
Use it like this:
"test" in withDB { }
This allows you, for example, to use an in-memory database for speeding up your unit tests.
You can access the DB instance as play.api.db.DB if you need it. You'll also need to import play.api.Play.current.
Use FakeApplication to read your DB configuration and provide a DB instance.
def withDB[T](code: => T): T =
// Create application to run database evolutions
running(FakeApplication(additionalConfiguration = Map(
"evolutionplugin" -> "disabled"))) {
import play.api.Play.current
val database = play.api.db.DB
Evolutions.applyEvolutions(database)
withSession(code)
Evolutions.cleanupEvolutions(database)
}
Use it like this:
"test" in withDB { }