jeudi 31 décembre 2015

TDD with slick and sqlite

So I'm trying to test my database directly instead of mocking stuff here. While mocking is fine and dandy in some cases, I want to explicitly test the database here.

See the following test-class:

package models

import org.scalatest.{BeforeAndAfter, Matchers, FlatSpec}
import org.scalatest.concurrent.ScalaFutures
import slick.driver.SQLiteDriver.api._
import scala.concurrent.ExecutionContext.Implicits.global
import org.scalatest.time.{Millis, Seconds, Span}
import org.scalactic.StringNormalizations._
import scala.concurrent.Future

/**
  * Created by Teolha on 30.12.15.
  */
class BookTest extends FlatSpec with Matchers with ScalaFutures with BeforeAndAfter {
  implicit val defaultPatience =
    PatienceConfig(timeout = Span(120, Seconds), interval = Span(10, Millis))

  val db = Database.forURL("jdbc:sqlite:/home/teolha/test.sqlite", driver = "org.sqlite.JDBC")

  private val books = Books.all

  before {
    db.run(setup)
  }

  after {
    db.run(tearDown)
  }

  val setup = DBIO.seq(
    (books.schema).create
  )

  val tearDown = DBIO.seq(
    (books.schema).drop
  )

  "Books" should "be empty at the beginning" in
  {
    whenReady(db.run(books.result))
    {
      result =>
      {
        result shouldBe empty
      }
    }
  }

  "Books" should "be a Sequence of Books with the appropriate length" in
  {
    // Preparation
    db.run(
      DBIO.seq
      (
        Books.add(0, "Awesome Title #1"),
        Books.add(1, "Gorgeous Sequel #2"),
        Books.add(2, "Bombastic prequel")
      )
    )

    whenReady(db.run(books.result))
    {
      result =>
      {
        result should have length 3
        result shouldBe a [Seq[_]] // Remember type erasure
        result(0) shouldBe a [Book]
      }
    }
  }

  "Books" should "be insertable as well as removable" in
  {
    whenReady(db.run(books.result))
    {
      result => result shouldBe empty
    }

    db.run(
      DBIO.seq
      (
        Books.add(0, "Awesome Title #1")
      )
    )

    whenReady(db.run(books.result))
    {
      result =>
      {
        result should have length 1
        result(0).title should equal ("nathanael mondae and the spear of destiny") (after being lowerCased)
      }
    }

    db.run(
      DBIO.seq
      (
        Books.delete(1)
      )
    )

    whenReady(db.run(books.result))
    {
      result => result shouldBe empty
    }
  }

  "Books" should "have a unique order" in
  {
    // Preparation
    db.run(
      DBIO.seq
      (
        Books.add(0, "Awesome Title #1"),
        Books.add(1, "Gorgeous Sequel #2"),
        Books.add(1, "Bombastic prequel")
      )
    )

    whenReady(db.run(books.result))
    {
      result => result should have length 2
    }
  }
}

Now the problem I have is, that these tests are completely non-deterministic. Sometimes they all run, and then I get an exception:

The future returned an exception of type: java.sql.SQLException, with message: [SQLITE_BUSY] The database file is locked (database is locked).

I'm really at my wits end here. How can I go about testing that kind of stuff? It's a local database and it's definitely not complicated right now.

Aucun commentaire:

Enregistrer un commentaire