2016-03-08

Longevity Builds Database Integration Tests For You

Longevity - a persistence framework for Scala and NoSQL - provides a variety of tools to help you test your database application. In tests where you don't want to mock your repositories, but you want to avoid the overhead of persisting to a real database, longevity provides you with a suite of fully functional in-memory repositories. There is also a test class that you can extend to test your database queries - you basically just have to build your queries, and the base class does the rest of the work for you. Finally, longevity provides you with a test class that will exercise all the basic CRUD operations for all your repositories against a test database. In this article, we'll take a look at how we go about setting up the CRUD tests.

With longevity, you provide us with your domain model, and we give you back a longevity context. The longevity context contains your repositories. For example, let's say we are building a simple blogging application, and we have three kinds of persistent objects: users, blog posts, and blogs. We build our subdomain like so:

    import longevity.subdomain._

    val subdomain = Subdomain(
      "blogging",
      EntityTypePool(User, BlogPost, Blog))

For more details on what the User, Blog, and BlogPost classes and companion objects look like, please read about building your domain model in the user manual.

Now let's build our longevity context. We'll specify Cassandra as our back end:

    import longevity.context.LongevityContext
    import longevity.context.Cassandra

    val context = LongevityContext(subdomain, Cassandra)

Now we can pull our standard set of repositories from there:

    val repoPool = context.repoPool

The repo pool is a TypeKeyMap, which allows you to pull out repositories by aggregate type:

    import longevity.persistence.Repo

    val userRepo: Repo[User] = repoPool[User]
    val blogRepo: Repo[Blog] = repoPool[Blog]
    val blogPostRepo: Repo[BlogPost] = repoPool[BlogPost]

The repository API supports all the basic CRUD operations, as well as queries.

In our test suite, some of our tests will want to run against an actual Cassandra database, but using a test database, and not the production database. For these tests, the longevity context provides us an alternative set of repositories:

    val testRepoPool = context.testRepoPool
    val testUserRepo: Repo[User] = testRepoPool[User]

For tests in which you don't want to mock your repositories, but you want to avoid the overhead of a real database, longevity provides fully functional in-memory repositories:

    val inMemUserRepo: Repo[User] =
      context.inMemTestRepoPool[User]

Now let's exercise the repo CRUD operations - Repo.create, Repo.retrieve, Repo.update, and Repo.delete - against the test database. The longevity context provides you with a ScalaTest suite that does exactly that:

    import scala.concurrent.ExecutionContext.Implicits.global


    val crudSpec: org.scalatest.Suite =
      longevityContext.repoCrudSpec

Typical ScalaTest execution usually scans for top-level classes, so we can embed our crudSpec in a top-level org.scalatest.Suites to get it to run as part of our test suite:

    import org.scalatest.Suites

    class BloggingCrudSpec extends Suites(crudSpec)

Running the BloggingCrudSpec will test the behavior of all the CRUD operations for all three of our aggregates, giving us assurance that the software and the database are properly integrated.

For more details on how this all works, please see the chapter on testing in the longevity user manual.

When we use an ORM or a database driver to do our persistence, we commonly dedicate an entire module of our test suite to assuring that the basic CRUD operations of our persistence layer work correctly when connecting to a real database. These tests are important, because getting our persistence layer to integrate with a real database is tricky and error-prone. But they are hard to write and maintain, representing a significant drain on productivity. Why not try a framework that does the hard work for you? We want you to focus your efforts on your domain and your business logic. We'll handle the persistence for you.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.