1
votes

Scala noob here.

I currently try to create functional tests for a Play (Scala) based web application using specs2. The examples themselves are simple, i.e.:

class SignInSpec extends PlaySpecification {

  // bring the workflow steps in scope and instrument browser with them    
  import utils.WorkflowSteps.AuthSteps

  "An activated user".should {
    "be able to sign in to the admin console" in new WithDbData(webDriver = WebDriverFactory(FIREFOX)) {

      // this should be: browser.signIn(testData.manager)
      // with the manager already persisted in the database
      browser.signIn(Manager(None, "[email protected]", "12341234", "John", "Doe", List("admin")))
    }
  }
}

What I'd like to achieve is to feed each example with a defined set of test data, some of which will already be persisted in the database. So I need a setup and a teardown method around each example that prepares a TestData case class, fills it with appropriate data and persists some of it so that the example can start with a defined database state. Ultimately I want a plugin mechanism where the plugs defined the test data for a set of examples (think of it as an application of the loan pattern).

What I did so far:

  • I tried to use some flavour of Around, but I don't know how to feed the data into the example as I'd have to add an additional return value.
  • I tried specs2's ForEach context, but that conflicts with Play's WithBrowser
  • I played with implicit vals, but again I don't know how to add an implicit parameter to the block that is transformed from a constructor to a function call parameter using DelayedInit

Any ideas how to proceed to achieve the following ?

  • Extending the specification or the example from an additional trait or class that calls the example with a single parameter TestData
  • This additional trait or class should be able to prepare test data and persist parts of it
  • This additional trait or class should be compatible with WithBrowser
2

2 Answers

0
votes

One approach is using so called "loan fixtures":

     def withTestData(test: TestData => Unit) = {
       val data = setupTestData() 
       try { 
         test(data)
       } finally {
         destroyTestData(data)
       }
     }



    "An activated user" should "be able to sign in to the admin console" in withTestData { data =>
       new WithDbData(webDriver = WebDriverFactory(FIREFOX)) {
         browser.signIn(data.manager)
       }
     }

etc ..

0
votes

One solution could be the following:

 case class TestData(manager: Manager) extends WithDbData(webDriver = WebDriverFactory(FIREFOX))


 class SignInSpec extends PlaySpecification with ForEach[TestData] {

   // bring the workflow steps in scope and instrument browser with them    
   import utils.WorkflowSteps.AuthSteps

   "An activated user".should {
     "be able to sign in to the admin console" in { data: TestData =>
        import data._

        browser.signIn(manager)
     }
   }

   def foreach[R : AsResult](f: TestData => R): Result = ???
 }

This is at the expense of having to import data._ but this also avoids the double nesting of the previous solution.