Playframework 2.6 [Scala]: How to run my setup tests before any actual essential tests? - scala

I want to know in what order the tests are running, because I want to run
my initial test setup tests only once before all the tests start running.
If I have one initial setup test class, and one essential test class it would be fine:
class EssentialTesting #Inject()(setupTests: SetupTest) extends ....{
setupTests.runInitialSetup()
.....
}
However if I have number of testings classes the setupTests.runInitialSetup will be repeated in each class. How to deal with this duplication?

Make your Setups class like:
class SetUpTest extends SpecificationLike with BeforeAndAfterAll{
override def beforeAll() = {
// runs before each test
}
override val afterAll() = {
// runs after each test
}
}
Now in your test file, you can extend your SetUpTest, like :
class Test extends PlaySpecification with SetupTest
Now you don't need to call the runinitialsetup every time, just put it into beforeAll method and it will get executed before each test. And SpecificationLike is required as BeforeAndAfterAll has self type reference for SpecificationLike.

Related

initialize container in test container before before all

I tried to write a group of tests with a test container. Test container needs to initialize override val container = PostgreSQLContainer() in test class body. I want to make a group of tests which will work with prepared test data inserted to DB. I tried to use beforeAll from org.scalatest, but it executes before initializing the container and there is an NPE. Could you rewrite code to get correct inserted test data.
class MysqlSpec extends FlatSpec with ForAllTestContainer with BeforeAndAfterAll {
override val container = MySQLContainer()
override protected def beforeAll(): Unit = {
super.beforeAll()
Class.forName(container.driverClassName)
val connection = DriverManager.getConnection(container.jdbcUrl, container.username, container.password)
// insert some records
}
"Mysql container" should "be started" in {
Class.forName(container.driverClassName)
val connection = DriverManager.getConnection(container.jdbcUrl, container.username, container.password)
val prepareStatement = connection.prepareStatement("select 1")
// check the records
}
}
I think you've mixed in the traits in the wrong order. Try BeforeAndAfterAll with ForAllTestContainer instead of ForAllTestContainer with BeforeAndAfterAll.
Those two traits both override the run method and call super.run in the process. If you use ForAllTestContainer with BeforeAndAfterAll, your class will inherit the run method from BeforeAndAfterAll, which will call beforeAll and then call super.run, meaning ForAllTestContainer's run implementation, and that will start the container. But you need it to go the other way around, and the order here is controlled by the order of the with clauses.
Any more questions as to why implementation inheritance is a bad idea?

When I run my test suites they fail with PSQLException: FATAL: sorry, too many clients already

I'm writing tests for my Play application and I want to run them with a real server so that I can fake all the answers from the external services.
In order to do that I extend PlaySpec and GuiceOneServerPerSuite and I override the method fakeApplication to create my routes and give them to the Guice Application
class MySpec extends PlaySpec with GuiceOneServerPerSuite {
override def fakeApplication(): Application =
GuiceApplicationBuilder().appRoutes(app => {
case ("POST", "/url/") => app.injector.instanceOf(classOf[DefaultActionBuilder]) { Ok }
}).globalApp(true).build()
"Something" should {
"work well" in {
val wsClient = app.injector.instanceOf[WSClient]
val service = new MyService(wsClient)
service.method() mustBe ""
app.injector.instanceOf[DBApi].databases().foreach(_.getConnection().close())
}
}
}
I have multiple test suites like this one and if I run them alone they work fine, but if I run them all together they fill up the connection pool and then everything fails with: org.postgresql.util.PSQLException: FATAL: sorry, too many clients already.
My considerations: I think it happens because at each test suite a new Play Guice Application is created. I also tried to close the connections of all databases manually but didn't solve the problem.
We had the same problems, so we are separating these 2 use cases (running all or just one Test-Suite).
This makes running all tests much faster - as Play Environment is only started once.
The Suite looks like:
class AcceptanceSpecSuite
extends PlaySpec
with GuiceOneAppPerSuite
with BeforeAndAfter {
// all specs
override def nestedSuites: immutable.IndexedSeq[AcceptanceSpec] = Vector(
// api
new DatabaseTaskSpec,
new HistoryPurgeTaskSpec,
...
)
override def fakeApplication(): Application =
// your initialization
}
Now each Spec looks like:
#DoNotDiscover // important that it is run only if called explicitly
class DatabaseTaskSpec extends AcceptanceSpec {
...
The Parent class now we can switch between GuiceOneServerPerSuite and ConfiguredApp:
trait AcceptanceSpec
extends PlaySpec
you need:
// with GuiceOneServerPerSuite // if you want to test only one Test
with ConfiguredApp // if you want to test all
with Logging
with ScalaFutures
with BeforeAndAfter {
...
I know it's a bit of a hack - so I am also interested in a more elegant solution;).
You can put your DB instance as a singleton, if you do that, he won´t create multiple instance, therefore won´t fill the connection pool.
Something like that:
#Singleton
object TestDBProperties extends DBProperties {
override val db: Database = Database.forURL(
url = "jdbc:h2:mem:testdb;MODE=MYSQL;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE;",
driver = "org.h2.Driver")
}
Hope this helps.

How to Test a Play Application that extends a custom trait

I'm having trouble writing tests for a mixin to my Play application that runs in it's own thread separate from play. I've tried over-writing WithApplication.provideApplication method with no luck. I get an inheriting conflicting methods error. (one from the real app "MyRunnableSystemWrapper", one from my mocked fake mixin called "MyMockedSystemWrapper").
execute(system) runs my system that is tested elsewhere and has sideaffects (connects to networked services, thus failing this test when such things are not available. Good news is I have a mocked service of my system wrapper that uses a system which does NOT have side affects and DB/Network calls are mocked out. However I do not know how to give THIS MOCKED version of my app to "WithApplication" test.
Reduced Code for clarity:
class Application extends Controller with MyRunnableSystemWrapper {
val pool: ExecutorService = Executors.newFixedThreadPool(1)
val system = new MyRunnableSystem() //system is abstract in MRSW ^^^ above
pool.execute(system)
def index = Action {
OK("HI")
}
}
My Test:
class MyAppTest(implicit ee: ExecutionEnv) extends Specification {
abstract class WithMyMockApp extends WithApplication {
def provideApplication = new controllers.Application with MyMockedSystemWrapper // This imports MyRunnableSystemWrapper
}
"Sending a GET request" should {
"Respond with OK" in new WithMyMockApp {
val response = route(app, FakeRequest(GET, "/")).get
status(response) mustEqual OK
}
}
}
If I'm not running my Runnable in the correct place and should be calling it somewhere else to make this testing easier, let me know!
You could inject your system wrapper instead of extending it
trait SystemWrapper {
def execute(system: RunnableSystem)
}
class MyRunnableSystemWrapper extends SystemWrapper {...}
class MyMockedSystemWrapper extends SystemWrapper {...}
class Application #Inject() (systemWrapper SystemWrapper) extends Controller {
Then you need to tell Guice which implementation of SystemWrapper you want for runtime and which one for test. One way of doing this is by using different Guice modules for runtime/test which you set in your .conf files.

Spark Unit Testing: How to initialize sc only once for all the Suites using FunSuite

I want to write spark unit test cases and I am using FunSuite for it.
But i want that my sparkContext is initialized only once , used by all the Suites and then is killed when all Suites completes.
abstract class baseClass extends FunSuite with BeforeAndAfter{
before {
println("initialize spark context")
}
after {
println("kill spark context")
}
}
#RunWith(classOf[JUnitRunner])
class A extends baseClass{
test("for class A"){
//assert
}
#RunWith(classOf[JUnitRunner])
class B extends baseClass{
test(for class b){
//assert
}
}
but when i run sbt test
I can see println statement baseClass has been called from both the tests. Obsiously When the object is created for both the classes A and B , Abstract
baseclass is called.
But then how can we achieve my purpose i.e spark context is iniliazed only once while all the test cases are run
Option 1: Use the excellent https://github.com/holdenk/spark-testing-base library that does exactly that (and provides many other nice treats). After following the readme, it's as simle as mixing-in SharedSparkContext instead of your baseClass, and you'll have an sc: SparkContext value ready to use in your test
Option 2: to do it yourself, you'd want to mix-in BeforeAndAfterAll and not BeforeAndAfter, and implement beforeAll and afterAll, which is exactly what the above-mentioned SharedSparkContext does.
I strongly recommend using the spark-testing-base library in order to manage the lifecycle of a sparkContext or sparkSession during your tests.
You won't have to pollute your tests by overriding the beforeAll, afterAll methods and managing the lifecycle of the sparkSession/sparkContext.
You can share one sparkSession/sparkContext for all the tests by overriding the following method :
def reuseContextIfPossible: Boolean = true
for more details : https://github.com/holdenk/spark-testing-base/wiki/SharedSparkContext
I hope it helps!
If you really want to share the context between suites - you'll have to make it static. Then you can use a lazy value to make it start on first use. As for shutting it down - you can leave it to the automatic Shutdown hook created each time a context is created.
It would look something like:
abstract class SparkSuiteBase extends FunSuite {
lazy val sparkContext = SparkSuiteBase.sparkContext
}
// putting the Spark Context inside an object allows reusing it between tests
object SparkSuiteBase {
private lazy val sparkContext = ??? // create the context here
}

Little confused on the usefulness of beforeAll construct in ScalaTest

I have more of a philosophical confusion in-regards to the usefulness of methods like 'beforeAll' in scalaTest.
I have been looking for an answer why the need to even have constructs like beforeAll? I do understand that there is a reason why this design decision was taken but not able to think it through. Can anyone help?
e.g.
Suggested way as per tutorials online,
class TestExample extends FunSuite with BeforeAndAfterAll {
private var _tempDir: File = _
protected def tempDir: File = _tempDir
override def beforeAll(): Unit = {
super.beforeAll()
_tempDir = Utils.createTempDir(namePrefix = this.getClass.getName)
}
test("...") {
// using the variable in the function
}
}
vs
class TestExample extends FunSuite with BeforeAndAfterAll {
private val tempDir: File = Utils.createTempDir(namePrefix =
this.getClass.getName)
}
test("...") {
// Use the initialized variable here.
}
If you have cleanup to do in afterAll, I think it is symmetric to do setup in beforeAll. Also if you need to do some side effect that doesn't involve initializing instance variables, that can go in beforeAll. In the example you gave, though, where you don't have any cleanup to do in afterAll and all you're doing before all tests is initializing instance variables, I'd do with plain old initialization.
One other difference between val initializers and beforeAll is val initializers happen when the class is instantiated, whereas beforeAll happens later, when the instance is executed. If you want to delay the initialization until the class is run, you can use lazy vals.
One point worth noting is that some runners (such as the ScalaTest ant task, and Intellij IDEA), will instantiate all tests instances before running any tests. If your setup code happens to interact with any global variables or external state, then you probably want to defer those interactions until the test is run.
As a simple (contrived) example, suppose your code under test includes
Object Singleton {
var foo = ""
}
and you have two test classes:
class Test1 extends FunSuite {
Singleton.foo = "test1"
test("...") {
Singleton.foo should be("test1")
}
}
class Test1 extends FunSuite {
Singleton.foo = "test2"
test("...") {
Singleton.foo should be("test2")
}
}
If both classes are instantiated before any tests are run, then at least one of your two tests will fail. Conversely, if you defer your initialize work until beforeAll, you'll not see the same interference between tests.