Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better way to compose test fixtures in ScalaTest

We have test fixtures using loan pattern. Leveraging this pattern to create "seed data" needed for a test to run. when test is dependent on data For e.g. following

"save definition" should {
"create a new record" in withSubject { implicit subject =>
  withDataSource { implicit datasource =>
    withFormType { implicit formtype =>

        val definitn = DefinitionModel(-1, datasource.id, formtype.id, subject.role.id, Some(properties))
    }
  }
}

Where withSubject, withDataSource, withFormType are test fixtures returning subject, dataSource, formType data respectively from database. withDataSource fixture requires subject implicitly. Building DefinitionModel requires datasource.id and formtype.id. so depending on the data requirement of a test calling such data builder fixtures is creating a lot of nested fixture situation. Is there a better way to "compose" /structure such fixtures?

like image 254
Vikas Pandya Avatar asked Mar 04 '15 03:03

Vikas Pandya


2 Answers

The answer given by @Nader Hadji Ghanbari still holds. I would just like to add that since version 3.x.x of scalatest the traits changed names. Copying from the migration guide:

Mixin traits that override withFixture

4) In 3.0.0, the withFixture method has been moved from Suite to a new trait, TestSuite. This was done to make room for a withFixture method with a different signature in AsyncTestSuite. If you factored out a withFixture method into a separate "suite mixin" trait, you'll need to change "Suite" to "TestSuite" and "SuiteMixin" to "TestSuiteMixin". For example, given this trait from 2.2.6:

trait YourMixinTrait extends SuiteMixin { this: Suite =>
 abstract override def withFixture(test: NoArgTest): Outcome = {
   // ...
 }
}

You will need to add the "Test" prefix, like this:

trait YourMixinTrait extends TestSuiteMixin { this: TestSuite =>
 abstract override def withFixture(test: NoArgTest): Outcome = {
   // ...
 }
}
like image 142
Lukasz Avatar answered Oct 23 '22 12:10

Lukasz


Trait

trait is your friend. Composition is one of the requirements traits cover very nicely.

Composing traits

From Scala Test Docs

Composing fixtures by stacking traits

In larger projects, teams often end up with several different fixtures that test classes need in different combinations, and possibly initialized (and cleaned up) in different orders. A good way to accomplish this in ScalaTest is to factor the individual fixtures into traits that can be composed using the stackable trait pattern. This can be done, for example, by placing withFixture methods in several traits, each of which call super.withFixture.

For instance you can define the following traits

trait Subject extends SuiteMixin { this: Suite =>

  val subject = "Some Subject"

  abstract override def withFixture(test: NoArgTest) = {
    try super.withFixture(test) // To be stackable, must call super.withFixture
    // finally clear the context if necessary, clear buffers, close resources, etc.
  }
}

trait FormData extends SuiteMixin { this: Suite =>

  val formData = ...

  abstract override def withFixture(test: NoArgTest) = {
    try super.withFixture(test) // To be stackable, must call super.withFixture
    // finally clear the context if necessary, clear buffers, close resources, etc.
  }
}

Then you can bring this traits to your test context by just mixing them in:

class ExampleSpec extends FlatSpec with FormData with Subject {

    "save definition" should {
        "create a new record" in {

            // use subject and formData here in the test logic            

        }
    }

}

Stackable Traits

For more info on Stackable Traits Pattern you can refer to this article

like image 4
Nader Ghanbari Avatar answered Oct 23 '22 10:10

Nader Ghanbari