How to initialize fixture once for all tests in scalatest? - scala

According to documentation, fixtures can be passed to tests like this:
def withFixture(test: OneArgTest) = {
val f = veryLengthyInitialization(test.configMap)
withFixture(test.toNoArgTest(f))
}
describe("Some test") {
it("should succeed") { f =>
f.doSomething()
// ...
}
// many other tests
// ...
}
Problem is that the initialization is run for each test, and it takes a very long time, so I would like it to run just once. Documentation suggests an alternative:
override def beforeAll(configMap: ConfigMap) {
val fOnce = veryLengthyInitialization(configMap)
// but how do I pass f to the tests?
// ugly workaround:
f = fOnce
}
var f: InitType = null
describe("Some test") {
it("should succeed") { // hack: no parameter, use var instead
f.doSomething()
// ...
}
// many other tests
// ...
}
It works, but my understanding is that null should be avoided, and it's a bit silly to rely on mutation for something as basic as this. What is the correct way to write such tests?

I don't think that there is a solution that is good in all aspects for this issue. One thing I do sometime to avoid the var is structuring the test as follows:
class SomeTest extends Spec {
def initFixtures(): SomeFixtureType = ???
lazy val fixtures = initFixtures()
describe("Some test") {
it("should succeed") in {
fixtures.doSomething()
// ...
}
}
}
In this way I don't need to use the beforeAndAfterAll thing, but you can if you want to guarantee that the fixtures are initialised before the test as follows:
override def beforeAll() {
super.beforeAll()
fixtures
}
It can also be handy when dealing with asynchronous initialisation since you could have something like:
class SomeTest extends Spec {
def initFixtures(): Future[SomeFixtureType] = ???
lazy val fixtures = initFixtures()
describe("Some test") {
it("should succeed") in {
whenReady(fixtures.flatMap {
f.doSomething()
// ...
}) { res => doSomeChecks(res) }
}
}
}
Having both initFixtures and fixtures is most useful in this case as you can have some tests re-initialise the system and act in isolation if they need to do effectful stuffs (e.g. use a database).

I'm not sure if the below is something better:
trait DoSomething {
var f:InitType = _
def doSomething = f.doSomething
}
class MyTestSpec extends DoSomething {
override def beforeAll(configMap: ConfigMap) {
val fOnce = veryLengthyInitialization(configMap)
f = fOnce
}
it("should succeed") {
doSomething()
}
}
For any tests you need a f variable to do something, you could extend the trait and initialize it in your beforeAll methods, in addition, you could even override the doSomething in your test.

Related

Mocking scala object called by under another object

I am trying to write unit test for a function under object1.
object Object1 {
def main(sysArgs: Array[String]): Unit = {
val inputDF: DataFrame = UtilObject.getInput()
}
}
object UtilObject {
def getInput(){
...
}
}
To write Unit test, I am using MockitoSugar.
"object1Main" should "should make correct calls" in {
val inputArgs = Array("abc")
val util = mock[UtilObject.type]
when(util.getInput().thenReturn(inputData))
Object1.main(inputArgs)
}
While running the test, it doesn't consider the util mock and just execute the getInput() function.
I think I am missing some sort of injection here. Any ideas?
Thanks in advance!
Mocking Scala objects should be impossible conceptually speaking. An object in Scala is a pure singleton. That means there can only be one member of that type at any time.
mockito-scala can mock Scala objects via reflection. I'll use a result type of String, instead of a DataFrame, but the idea is the same:
object UtilObject {
def getInput(): String = {
// ...
"done"
}
}
object Object1 {
def main(sysArgs: Array[String]): String = {
val inputDF: String = UtilObject.getInput()
inputDF
}
}
// in test file:
"object1Main" should {
"should make correct calls" in {
val inputArgs = Array("abc")
withObjectMocked[UtilObject.type] {
UtilObject.getInput() returns "mocked!"
Object1.main(inputArgs) shouldBe "mocked!"
}
Object1.main(inputArgs) shouldBe "done"
}
}
This mocks the singleton's method only inside the block of withObjectMocked.
Usually such powerful techniques often tend to be overused or misused, so I don't generally recommend them, unless the design cannot be refactored.
Luckily, yours can: the easiest way is to use Dependency Injection with a class or a function. For DI with a class you require to convert the object being mocked into a class:
class UtilObject {
def getInput(): String = {
// ...
"done"
}
}
object Object1 {
def main(sysArgs: Array[String], ut: UtilObject): String = {
val inputDF: String = ut.getInput()
inputDF
}
}
// in test file:
"object1Main" should {
"should make correct calls" in {
val inputArgs = Array("abc")
val util = mock[UtilObject]
when(util.getInput()).thenReturn("mocked!")
Object1.main(inputArgs, util) shouldBe "mocked!"
}
}
For DI with a function you need to lift the method you want to mock into a function:
object UtilObject {
def getInput(): String = {
// ...
"done"
}
}
object Object1 {
def main(sysArgs: Array[String], f: () => String = UtilObject.getInput): String = {
val inputDF: String = f()
inputDF
}
}
// in test file:
"object1Main" should {
"should make correct calls" in {
val inputArgs = Array("abc")
val f = mock[() => String]
when(f()).thenReturn("mocked!")
Object1.main(inputArgs, f) shouldBe "mocked!"
}
}
Since the function takes no arguments, you can convert it into a by-name parameter. I'll leave that to you.
Lastly, another way is to create a trait with the method you want to mock and extend that with the object. But now Object1 requires being a class and have a reference to the object being mocked:
object UtilObject extends Utils {
def getInput(): String = {
// ...
"done"
}
}
trait Utils {
def getInput(): String
}
class Object1 {
val uo: Utils = UtilObject
def main(sysArgs: Array[String]): String = {
val inputDF: String = uo.getInput()
inputDF
}
}
// in test file:
"object1Main" should {
"should make correct calls" in {
val classUnderTest = new Object1 {
override val uo = mock[Utils]
}
val inputArgs = Array("abc")
when(classUnderTest.uo.getInput()).thenReturn("mocked!")
classUnderTest.main(inputArgs) shouldBe "mocked!"
}
}
As you can see, there are a few ways to go. Neither is inherently wrong. It mostly depends on your requirements(e.g. you can't afford adding a dependency just for one UT), needs(e.g. does the object I am testing really needs to be an object or can I make it a class?), guidelines (e.g. your team decided to avoid using powerful testing frameworks that rely on reflection and use DI as much as possible instead) and personal preferences.

Async before and after for creating and dropping scala slick tables in scalatest

I'm trying to figure out a way to have async before and after statements where the next test cases aren't run until the completion of the action inside of the test case. In my case, it is the creating and dropping a table inside of a database
val table = TableQuery[BlockHeaderTable]
val dbConfig: DatabaseConfig[PostgresDriver] = DatabaseConfig.forConfig("databaseUrl")
val database: Database = dbConfig.db
before {
//Awaits need to be used to make sure this is fully executed before the next test case starts
//TODO: Figure out a way to make this asynchronous
Await.result(database.run(table.schema.create), 10.seconds)
}
"BlockHeaderDAO" must "store a blockheader in the database, then read it from the database" in {
//...
}
it must "delete a block header in the database" in {
//...
}
after {
//Awaits need to be used to make sure this is fully executed before the next test case starts
//TODO: Figure out a way to make this asynchronous
Await.result(database.run(table.schema.drop),10.seconds)
}
Is there a simple way I can remove these Await calls inside of my before and after functions?
Unfortunately, #Jeffrey Chung's solution hanged for me (since futureValue actually awaits internally). This is what I ended up doing:
import org.scalatest.{AsyncFreeSpec, FutureOutcome}
import scala.concurrent.Future
class TestTest extends AsyncFreeSpec /* Could be any AsyncSpec. */ {
// Do whatever setup you need here.
def setup(): Future[_] = ???
// Cleanup whatever you need here.
def tearDown(): Future[_] = ???
override def withFixture(test: NoArgAsyncTest) = new FutureOutcome(for {
_ <- setup()
result <- super.withFixture(test).toFuture
_ <- tearDown()
} yield result)
}
The following is the testing approach that Dennis Vriend takes in his slick-3.2.0-test project.
First, define a dropCreateSchema method. This method attempts to create a table; if that attempt fails (because, for example, the table already exists), it drops, then creates, the table:
def dropCreateSchema: Future[Unit] = {
val schema = BlockHeaderTable.schema
db.run(schema.create)
.recoverWith {
case t: Throwable =>
db.run(DBIO.seq(schema.drop, schema.create))
}
}
Second, define a createEntries method that populates the table with some sample data for use in each test case:
def createEntries: Future[Unit] = {
val setup = DBIO.seq(
// insert some rows
BlockHeaderTable ++= Seq(
BlockHeaderTableRow(/* ... */),
// ...
)
).transactionally
db.run(setup)
}
Third, define an initialize method that calls the above two methods sequentially:
def initialize: Future[Unit] = for {
_ <- dropCreateSchema
_ <- createEntries
} yield ()
In the test class, mix in the ScalaFutures trait. For example:
class TestSpec extends FlatSpec
with Matchers
with ScalaFutures
with BeforeAndAfterAll
with BeforeAndAfterEach {
// ...
}
Also in the test class, define an implicit conversion from a Future to a Try, and override the beforeEach method to call initialize:
implicit val timeout: Timeout = 10.seconds
implicit class PimpedFuture[T](self: Future[T]) {
def toTry: Try[T] = Try(self.futureValue)
}
override protected def beforeEach(): Unit = {
blockHeaderRepo.initialize // in this example, initialize is defined in a repo class
.toTry recover {
case t: Throwable =>
log.error("Could not initialize the database", t)
} should be a 'success
}
override protected def afterAll(): Unit = {
db.close()
}
With the above pieces in place, there is no need for Await.
You can simplify #Jeffrey Chung
A simplified dropCreateSchema method:
def dropCreateSchema: Future[Unit] = {
val schema = users.schema
db.run(DBIO.seq(schema.dropIfExists, schema.create))
}
Also in the test class, I simplified beforeEach method that calls initialize. I removed an implicit conversion from a Future to a Try, and use onComplete callback:
override protected def beforeEach(): Unit = {
initialize.onComplete(f =>
f recover {
case t: Throwable =>
log.error("Could not initialize the database", t)
} should be a 'success)
}
override protected def afterAll(): Unit = {
db.close()
}

Do I have to avoid using objects if I want to unit-test them?

Say, I'm using some json libraries which provides an object Json:
object Json {
def unapply[T](jsonStr:String)(implicit converter:Converter[T]) { ... }
}
I can use it in my scala code like this:
class MyLoginController {
def login(request:Request) = {
val loginInfo = Json.unapply[LoginInfo](request.body)
// check(loginInfo.email)
// check(loginInfo.password)
}
}
It's works perfectly, but soon I found my self can't test it easily with mock. I can't find a way to mock the Json.unapply.
So I have to change my code to provide a trait and use dependency injection:
trait JsonParsable[T] {
def parse(jsonStr:String)(implicit converter:Converter[T])
}
object JsonParser extends JsonParsable[T] {
def parse(jsonStr:String)(implicit converter:Converter[T]) = Json.unapply(jsonStr)
}
class MyLoginController(jsonParser:JsonParsable[T]) {
def login(request:Request) = {
val loginInfo = jsonParser.parse[LoginInfo](request.body)
// check(loginInfo.email)
// check(loginInfo.password)
}
}
And when I write unit test, I will mock a JsonParsable for the MyLoginController:
val fakeParser = mock[JsonParsable]
// ...
val controller = new MyLoginController(fakeParser)
// ...
My question is, do I have to do this to avoid using objects, just in order to make it testable?
I found previous code is simple and easy, but the later one is more complex :(

specs2 After method runs before the example

I have the following test:
class Foo extends mutable.SpecificationWithJUnit {
sequential
"this example should run before the 'After' method" in new Context {
bar must beSome
}
class Context extends mutable.BeforeAfter with mutable.Around {
override def apply[T : AsResult](a: =>T): Result = {
lazy val result = super[Around].apply(a)
super[BeforeAfter].apply(result)
}
override def delayedInit(x: => Unit): Unit = around { try { before; x; Success() } finally { after }}
#Resource var barReader : BarReader = _
val bar = barReader.someBar
override def before : Any = { //some stuff}
def after: Any = {
bar = None
}
override def around[T : AsResult](t: =>T) = {
//spring context injection logic
AsResult.effectively(t)
}
}
}
}
I expect this test to pass but in reality what happens is that because of the delayed init, the after runs before the example. If I change the Context to a trait I lose the delayed init functionality. Is this a bug or am I doing something wrong?
**Edited:
This example will throw an NPE when the Context is a trait. What I expect to happen is that because of the delayed-init, the Context's constructor, which consequentially means the barReader.someBar will run only after the barReader has been injected.
Thanks
Netta
You should use a trait instead of a class for Context. If you use a class, delayedInit (hence after) will be triggered twice. Once for the body of the Context class and another time for the body of the anonymous class new Context. With a trait you don't get such a behavior:
class Foo extends mutable.SpecificationWithJUnit {
sequential
"this example should run before the 'After' method" in new Context {
bar must beSome
}
trait Context extends mutable.After {
var bar : Option[String] = Some("bar")
def after: Any = bar = None
}
}
Simple answer, looks like this can't be done.

By-Name-Parameters for Constructors

coming from my other question is there a way to get by-name-parameters for constructors working? I need a way to provide a code-block which is executed on-demand/lazy/by-name inside an object and this code-block must be able to access the class-methods as if the code-block were part of the class.
Following Testcase fails:
package test
class ByNameCons(code: => Unit) {
def exec() = {
println("pre-code")
code
println("post-code")
}
def meth() = println("method")
def exec2(code2: => Unit) = {
println("pre-code")
code2
println("post-code")
}
}
object ByNameCons {
def main(args: Array[String]): Unit = {
val tst = new ByNameCons {
println("foo")
meth() // knows meth() as code is part of ByNameCons
}
tst.exec() // ByName fails (executed right as constructor)
println("--------")
tst.exec2 { // ByName works
println("foo")
//meth() // does not know meth() as code is NOT part of ByNameCons
}
}
}
Output:
foo
method
pre-code
post-code
--------
pre-code
foo
post-code
This is because when you're making an instance like this:
val tst = new ByNameCons {
...
}
.. you're actually creating an anonymous class, like in java.
The above code is the same as:
val tst = new ByNameCons() { ... }
.. while the correct syntax for passing by-name is:
val tst = new ByNameCons( { ... } )
You cant omit parentheses the same way for constructors as with functions.
val tst = new ByNameCons( {
println("foo")
} )
Thought it is probably just easier to do this:
object ByNameCons {
def apply(code: => Unit) = new ByNameCons(code)
}
val tst = ByNameCons { // no "new" here -- can't mix traits either
println("foo")
}
I dont know why, but it appears that using {} or () when creating the class changes the behavior. Using the following class,
class Coder(code: => Unit) {
def exec = {
println("before")
code
println("after")}
}
}
scala> val brackets = new Coder {println("testing")}
testing
brackets: Coder = $anon$1#1af7a03
scala> brackets exec
before
after
Now instead if defined another way,
scala> val parens = new Coder(println("testing"))
parens: Coder = Coder#dca3ed
scala> parens exec
before
testing
after
as desired. It seems as if in the first notation, the compiler is interpreting the brackets as a block to be evaluated to Unit, instead of an anonymous function which, when called, evaluates to Unit.
FWIW, using ({ ... }) also works fine.