Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test methods based on Salat with ScalaTest

I'm writing a web-app using Play 2, Salat (for mongoDB bindin). I would like to test some methods, in the Lesson Model (for instance test the fact that I retrieve the right lesson by id). The problem is that I don't want to pollute my current DB with dummy lessons. How can I use a fake DB using Salat and Scala Test ? Here is one of my test file. It creates two lessons, and insert it into the DB, and it runs some tests on it.

LessonSpec extends FlatSpec with ShouldMatchers {
  object FakeApp extends FakeApplication()

  val newLesson1 = Lesson(
    title = "lesson1",
    level = 5,
    explanations = "expl1",
    questions = Seq.empty)
  LessonDAO.insert(newLesson1)

  val newLesson2 = Lesson(
    title = "lesson2",
    level = 5,
    explanations = "expl2",
    questions = Seq.empty)
  LessonDAO.insert(newLesson2)

  "Lesson Model" should "be retrieved by level" in {
    running(FakeApp) {
      assert(Lesson.findByLevel(5).size === 2)
    }
  }
  it should "be of size 0 if no lesson of the level is found" in {
    running(FakeApp) {
      Lesson.findByLevel(4) should be(Nil)
    }
  }

  it should "be retrieved by title" in {
    running(FakeApp) {
      Lesson.findOneByTitle("lesson1") should be(Some(Lesson("lesson1", 5, "expl1", List())))
    }
  }

}

I searched on the web but i can't find a good link or project that use Salat and ScalaTest.

like image 479
TeaBough Avatar asked Sep 28 '12 19:09

TeaBough


People also ask

How do I test a Scala script?

Test Scala applications using Scala TestOpen your project. icon in the sbt projects tool window to refresh your project or use the Reload project after changes in the build scripts option specified in the Build Tools settings to automatically refresh your project each time you make changes to build.

What is AnyFlatSpec?

class AnyFlatSpec extends AnyFlatSpecLikeFacilitates a “behavior-driven” style of development (BDD), in which tests are combined with text that specifies the behavior the tests verify.


2 Answers

Salat developer here. My recommendation would be to have a separate test only database. You can populate it with test data to put your test database in a known state - see the casbah tests for how to do this - and then test against it however you like, clearing out collections as necessary.

I use specs2, not scalatest, but the principle is the same - see the source code for the Salat tests.

Here's a good test to get you started: https://github.com/novus/salat/blob/master/salat-core/src/test/scala/com/novus/salat/test/dao/SalatDAOSpec.scala

Note that in my base spec I clear out my test database - this gets run before each spec:

trait SalatSpec extends Specification with Logging {

  override def is =
    Step {
      //      log.info("beforeSpec: registering BSON conversion helpers")
      com.mongodb.casbah.commons.conversions.scala.RegisterConversionHelpers()
      com.mongodb.casbah.commons.conversions.scala.RegisterJodaTimeConversionHelpers()

    } ^
      super.is ^
      Step {
        //        log.info("afterSpec: dropping test MongoDB '%s'".format(SalatSpecDb))
        MongoConnection().dropDatabase(SalatSpecDb)
      }

And then in SalatDAOSpec, I run my tests inside scopes which create, populate and/or clear out individual collections so that the tests can run in an expected state. One hitch: if you run your tests concurrently on the same collection, they may fail due to unexpected state. The solution is either to run your tests in isolated special purpose collections, or to force your tests to run in series so that operations on a single collection don't step on each other as different test cases modify the collection.

If you post to the Scalatest mailing list (http://groups.google.com/group/scalatest-users), I'm sure someone can recommend the correct way to set this up.

like image 76
prasinous Avatar answered Sep 29 '22 19:09

prasinous


In my applications, I use a parameter in application.conf to specify the Mongo database name. When initializing my FakeApplication, I override that parameter so that my unit tests can use a real Mongo instance but do not see any of my production data.

Glossing over a few details specific to my application, my tests look something like this:

// wipe any existing data
db.collectionNames.foreach { colName =>
  if (colName != "system.indexes") db.getCollection(colName).drop
}

app = FakeApplication(additionalConfiguration = Map("mongo.db.name" -> "unit-test"))
like image 22
Alex Varju Avatar answered Sep 29 '22 19:09

Alex Varju