Play is working fine when I am using sbt run. However, when I am trying to do such test:
#RunWith(classOf[JUnitRunner])
class MarketApiSpec extends Specification {
"Market API" should {
"load product list" in new WithApplication {
val completed = route(FakeRequest("GET", "/api/products")).get.map(x => Json.parse(x.body.toString()))
val jsonObject = Await.result(completed, Duration("1s"))
jsonObject.get("products").get(0).get("name").asText() must beEqualTo("Programmer");
}
}
}
By a sbt test I get such error exception:
[info] Market API should
[info] ! load product list
[error] RuntimeException: : java.lang.NoClassDefFoundError: Could not initialize class controllers.WebJarAssets$ (Action.scala:523)
[error] play.api.mvc.ActionBuilder$$anon$1.apply(Action.scala:523)
I googled a lot, however I didn't find the solution. I think its related to sbt somehow, but even giving a test scope doesn't help.
Related
I have hello world scala native app and wanted to run small scala test to this app I use the usual test command but it's throw an exception :
NativeMain.scala
object NativeMain {
val p = new Person("xxxx")
def main(args: Array[String]): Unit = {
println("Hello world")
}
}
class Person(var name: String)
}
NativeTest.scala
import org.scalatest.{FlatSpec, Matchers}
class NativeTest extends FlatSpec with Matchers {
"name" should "the name is set correctly in constructor" in {
assert(NativeMain.p.name == "xxxx")
}
}
I run test command in the sbt shell and got this error
[IJ]> test
[info] Compiling 1 Scala source to /home/****/Documents/ScalaNativeFresh/target/scala-2.11/classes...
[info] Compiling 1 Scala source to /home/****/Documents/ScalaNativeFresh/target/scala-2.11/test-classes...
[info] Compiling 1 Scala source to /home/****/Documents/ScalaNativeFresh/target/scala-2.11/test-classes...
[info] Linking (28516 ms)
[error] cannot link: #java.lang.Thread::getStackTrace_scala.scalanative.runtime.ObjectArray
[error] unable to link
[error] (nativetest:nativeLink) unable to link
[error] Total time: 117 s, completed Apr 2, 2019 3:04:24 PM
Any help or suggestions thank you :) ?
There is an open issue to add Add support for Scala Native #1112 and according to cheeseng:
3.1.0-SNAP6 and 3.2.0-SNAP10 are the only 2 versions (as of the time of writing) that supports scala-native
Try importing scalatest_native0.3_2.11 like so
libraryDependencies += "org.scalatest" % "scalatest_native0.3_2.11" % "3.2.0-SNAP10"
scalatest-native-example is a working example showing how to use scalatest with scala-native.
I'm using Play 2.4.6 with compile time dependency injection and ScalaTest. The controller's constructor has few parameters, and in an ApplicationLoader I create it.
Here is the code:
class BootstrapLoader extends ApplicationLoader {
def load(context: Context) = {
new AppComponents(context).application
}
}
class AppComponents(context: Context) extends BuiltInComponentsFromContext(context) with NingWSComponents {
lazy val router = new Routes(httpErrorHandler, authenticationController, applicationController, assets)
lazy val applicationController = new controllers.Application()
lazy val authenticationController = new controllers.Authentication()(configuration, wsApi.client)
lazy val assets = new controllers.Assets(httpErrorHandler)
}
class Authentication(implicit configuration: Configuration, val ws: WSClient) extends Controller {
def login = Action { implicit request =>
Unauthorized(s"${redirectUrl}")
}
}
class AuthenticationSpec extends PlaySpec with OneAppPerSuite {
implicit val configuration: Configuration = app.configuration
implicit val wsClient: WSClient = WS.client(app)
"when user not logged-in" should {
"return Status code Unauthorized(401) with redirect url" in {
1 mustEqual 2
}
}
}
When I'm running the test I'm getting the following error:
[info] Exception encountered when attempting to run a suite with class name: controllers.AuthenticationSpec *** ABORTED ***
[info] com.google.inject.ProvisionException: Unable to provision, see the following errors:
[info]
[info] 1) Could not find a suitable constructor in controllers.Authentication. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
[info] at controllers.Authentication.class(Authentication.scala:19)
[info] while locating controllers.Authentication
[info] for parameter 1 at router.Routes.<init>(Routes.scala:35)
[info] while locating router.Routes
[info] while locating play.api.test.FakeRouterProvider
[info] while locating play.api.routing.Router
[info]
[info] 1 error
[info] at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1025)
[info] at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051)
[info] at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:321)
[info] at play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:316)
[info] at play.api.Application$class.routes(Application.scala:112)
[info] at play.api.test.FakeApplication.routes(Fakes.scala:197)
[info] at play.api.Play$$anonfun$start$1.apply$mcV$sp(Play.scala:90)
[info] at play.api.Play$$anonfun$start$1.apply(Play.scala:87)
[info] at play.api.Play$$anonfun$start$1.apply(Play.scala:87)
[info] at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
FakeApplication use GuiceApplicationBuilder, which of course does not work.
What should I do to run such tests?
Thanks
override implicit lazy val app = new BootstrapLoader().load(
ApplicationLoader.createContext(
new Environment(
new File("."), ApplicationLoader.getClass.getClassLoader, Mode.Test)))
It works in Play 2.5.1
You are getting an error because the tests are not even able to start a application. That is happening because you are using Dependency Injection in your controllers (as the error message suggests) and you need to declare them as classes, instead of as objects. As you can see at the docs:
package controllers
import play.api.mvc._
class Application extends Controller {
def index = Action {
Ok("It works!")
}
}
If your controller has some dependency to be injected, you should use the #Inject annotation in your controller constructor (again, please see the docs). Per instance:
package controllers
import play.api.mvc._
import play.api.libs.ws._
import javax.inject._
class Application #Inject() (ws: WSClient) extends Controller {
// ...
}
You can also read the Compile Time Dependency Injection docs if you are using it instead of runtime DI.
If you use specs2 you can do it. see http://loicdescotte.github.io/posts/play24-compile-time-di/
But you loose the nice api.
Scalatest / scalatest-plus has done something funky with the DI (guice) :(
I'm facing the same problem as you. I don't have a satisfying solution, the following is a mere workaround:
I ended up putting
implicit def client:WSClient = NingWSClient()
in my WithApplicationLoader class
I also found https://github.com/leanovate/play-mockws which allows you to mock ws calls. But that's not what we want here.
my guess would be that the OneAppPerSuite trait isn't using your custom application loader. you may need to override the application construction that comes from that trait and make it use your custom loader.
looks like there is an example using scalatest here: http://mariussoutier.com/blog/2015/12/06/playframework-2-4-dependency-injection-di/
I use Scala, Play 2.4, and Slick 3 in my project. I have following DAO code and it works fine from end to end.
#Singleton()
class CompaniesDAO #Inject() (protected val dbConfigProvider: DatabaseConfigProvider) extends CompaniesComponent
with HasDatabaseConfigProvider[JdbcProfile] {
import driver.api._
}
However, I can't get it working as expected in my integration test because of dbConfig stuff. My integration test is below:
class CompaniesDaoIntegrationSpec extends FunSpec with OneServerPerSuite {
def companiesDao(implicit app: Application) = {
val app2CompaniesDAO = Application.instanceCache[CompaniesDAO]
app2CompaniesDAO(app)
}
describe("create") {
it("should create ") {
companiesDao.create...
}
}
}
If I don't put db properties in application.conf I got the following error:
[info] java.lang.RuntimeException: com.google.inject.ProvisionException: Unable to provision, see the following errors:
[info]
[info] 1) No implementation for play.api.db.slick.DatabaseConfigProvider was bound.
[info] while locating play.api.db.slick.DatabaseConfigProvider
[info] for parameter 0 at
It seems given the above code, Play application reads the db properties from configuration file which is located at /conf/application.conf.
My project setup is a bit different to this, as we have multiple environments so we have file structuers like:
/conf/local/application.conf
/conf/testing/application.conf
/conf/staging/application.conf
/conf/production/application.conf
When we run the play application using command like: activator run -Dconfig.resource=/conf/local/application.conf and everything work fine.
I want to do the same for integration spec like: activator test -Dconfig.resource=/conf/local/application.conf.
Play will read the specified config to run integration tests.
What's the best way to achieve that?
You have to make a trait and mix it in the test, and then it will work.
trait WithDatabaseConfig {
lazy val (driver, db) = {
val dbConfig = DatabaseConfigProvider.get[JdbcProfile](Play.current)
(dbConfig.driver, dbConfig.db)
}
}
I have no idea why, I'm a Scala beginner. Probably has to do something with not/running app or Guice. Found it in their samples folder at https://github.com/playframework/play-slick/blob/1.1.x/samples/json/test/DBSpec.scala
I've got a Play (v 2.2.0) app using Typesafe Slick (v 1.0.1), and I'm trying to write a test (specs2) that seeds a PostgreSQL database, then makes a call to various controller actions to validate the existence of the data. In my test, I have:
"Countries" should {
"initialize" in {
running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
AppDB.database.withSession {
implicit session: Session =>
AppDB.dal.create
AppDB.dal.seedForTests
AppDB.dal.Countries.findAll().size must be_>=(1)
}
}
}
by itself, this works fine. But, when I add another test action, like:
"respond to Index()" in {
val result = controllers.Countries.index()(FakeRequest())
status(result) must equalTo(OK)
}
my test fails with the message:
SQLException: Attempting to obtain a connection from a pool that has already been shutdown.
The relevant parts of the stacktrace are:
[error] SQLException: Attempting to obtain a connection from a pool that has already been shutdown.
[error] Stack trace of location where pool was shutdown follows:
[error] java.lang.Thread.getStackTrace(Thread.java:1503)
[error] com.jolbox.bonecp.BoneCP.captureStackTrace(BoneCP.java:559)
[error] com.jolbox.bonecp.BoneCP.shutdown(BoneCP.java:161)
[error] com.jolbox.bonecp.BoneCPDataSource.close(BoneCPDataSource.java:143)
[error] play.api.db.BoneCPApi.shutdownPool(DB.scala:414)
[error] play.api.db.BoneCPPlugin$$anonfun$onStop$1.apply(DB.scala:264)
[error] play.api.db.BoneCPPlugin$$anonfun$onStop$1.apply(DB.scala:262)
[error] scala.collection.immutable.List.foreach(List.scala:318)
[error] play.api.db.BoneCPPlugin.onStop(DB.scala:262)
...
I've tried moving both the FakeApplication(...) and AppDB.database.withSession blocks higher in the code, as well as wrapping the val result = controllers.Countries.index(...) code in an AppDB.database.withSession wrapper, but still have had no luck.
Thank you for any direction.
You can use AroundExample to initialise your DB and run your tests:
class CountriesSpec extends mutable.Specification with AroundExample {
def around[R : AsResult](r: =>R) =
running(FakeApplication(additionalConfiguration = inMemoryDatabase())) {
AppDB.database.withSession { implicit session: Session =>
AppDB.dal.create
AppDB.dal.seedForTests
AppDB.dal.Countries.findAll().size must be_>=(1)
// just AsResult(r) with the latest 2.2.3 specs2
AsResult.effectively(r)
}
}
"Countries" should {
"respond to Index()" in {
val result = controllers.Countries.index()(FakeRequest())
status(result) must equalTo(OK)
}
}
}
Could someone please help. I have Play2 project in which I need to test some DAO code.
I used documentaion from http://www.playframework.org/documentation/2.0.2/ScalaTest.
The test is very simple:
import models.Calendar
import org.specs2.mutable._
import play.api.test._
import play.api.test.Helpers._
class CalendarSpec extends Specification {
"Calendar model" should {
"be retrieved by id" in {
val fakeApp = FakeApplication()
running(fakeApp) {
lazy val calendarId= Calendar.addCalendar(
Calendar(subject="test",
upAccount = "mytest",
masterId = 1,
calendarType = 1,
isAllDayEvent = false,
hasAttachment = false,
category = "test",
instanceType = 1,
upName = "test" ))
lazy val Some(calendar) = Calendar.getCalendar(calendarId.get)
calendar.upAccount must equalTo("mytest")
}
}
}
}
And when I run 'sbt test' I get strange error:
[info] Calendar model should
[error] ! Fragment evaluation error
[error] ThrowableException: play.api.test.Helpers$.play$api$http$HeaderNames$_setter_$ACCESS_CONTROL_ALLOW_ORIGIN_$eq(Ljava/lang/String;)V (TraversableLike.scala:194)
[error] play.api.http.HeaderNames$class.$init$(StandardValues.scala:195)
[error] play.api.test.Helpers$.<init>(Helpers.scala:16)
[error] play.api.test.Helpers$.<clinit>(Helpers.scala:111)
[error] CalendarSpec$$anonfun$1$$anonfun$apply$1.apply(CalendarSpec.scala:13)
[error] CalendarSpec$$anonfun$1$$anonfun$apply$1.apply(CalendarSpec.scala:10)
[error] play.api.test.Helpers$.play$api$http$HeaderNames$_setter_$ACCESS_CONTROL_ALLOW_ORIGIN_$eq(Ljava/lang/String;)V
[error] play.api.http.HeaderNames$class.$init$(StandardValues.scala:195)
[error] play.api.test.Helpers$.<init>(Helpers.scala:16)
[error] play.api.test.Helpers$.<clinit>(Helpers.scala:111)
[error] CalendarSpec$$anonfun$1$$anonfun$apply$1.apply(CalendarSpec.scala:13)
[error] CalendarSpec$$anonfun$1$$anonfun$apply$1.apply(CalendarSpec.scala:10)
StackOverflow/Google knows nothing about this exception. Thanks in advance.
The stacktrace makes me think that a library is incorrect or missing in your classpath. This is why you are seeing "Helpers$." traces where the class constructor seems to be failing.
You can validate this by writing a small app in your test directory, without specs2 but using Play2's helper classes and see what happens.
I found solution - https://groups.google.com/forum/#!msg/play-framework/NSN9xfktUks/EwiG1Cc0C9oJ:
new play.core.StaticApplication(new java.io.File(".")) should be added to actualy start Play app so DAO calls can work in test.