Fast empty Raven DB sandbox databases for unit tests

Say you you have some NUnit/xUnit/Mspec tests that require a live Raven DB instance. Specifically:

  • You do not want your test to be affected by any existing documents, so ideally the Raven DB database would be completely empty.
  • Your test may span multiple document sessions, so doing it all within a single transaction and rolling it back is not an option.
  • You want your tests to run fast.

What are your options?

Raven DB currently has no DROP DATABASE or equivalent command. The recommended method is simply to delete Raven DB’s Server\Data or Server\Tenants directories, but this requires restarting the Raven DB service (expensive). Also any live document stores may throw an exception at this point.

Multi-tenanting

One option that Raven DB makes very cheap, however, is spinning up new database instances (aka tenants). In fact all you need to do is specify a new DefaultDatabase and the document store will spin a new database up for you. For example:

var store = new DocumentStore
    {
        Url = "http://localhost:8080",
        DefaultDatabase = "MyAppTests-" + DateTime.Now.Ticks
    };
store.Initialize();

// now you have an empty database!

Pretty easy huh? Here’s a little test helper I wrote to help manage these sandbox databases, stores and sessions. Here’s how you would use it in a tenant-per-fixture test:

[TestFixture]
public class When_doing_something
{
    [TestFixtureSetUp]
    public void SetUp()
    {
        RavenDB.SpinUpNewDatabase();

        using (var session = RavenDB.OpenSession())
        {
            // insert test data
        }
    }

    [Test]
    public void It_should_foo()
    {
        using (var session = RavenDB.OpenSession())
        {
            // run tests
        }
    }
}

You can grab it here as a gist on Github: https://gist.github.com/1940759.

Note that if you use this method, a number of sandbox databases will (of course) build up over time. You can clean these up you by simply deleting the Raven DB data directories. (See gist for an example batch file you can throw in your source control to do this.)

February 29, 2012

9 Comments

Ayende Rahien on March 1, 2012 at 10:15 pm.

Richard,

Why do you do it like this?
RavenDB contains explicit support for testing.

new EmbeddableDocuemntStore { RunInMemory = true}

This will give you RavenDB running in memory, no need to setup a new database.

Richard on March 3, 2012 at 4:51 pm.

@Ayende: how easy is it to browse/debug an in in-memory Raven database using the Raven DB Studio silverlight client?

Arnold Zokas on March 11, 2012 at 10:56 pm.

Hi Richard,

Most debugging situations shouldn’t require use of RavenDB studio, but for those that do you can expose the embedded database via HTTP:


var documentStore = new EmbeddableDocumentStore
{
DataDirectory = "Data",
RunInMemory = true,
UseEmbeddedHttpServer = true
};

That way you get both the ability to browse and the performance benefits of using an embedded document store. Also, your tests would no longer have a dependency on an external service.

Richard on March 13, 2012 at 2:51 pm.

@Arnold: ah I didn’t know you could do that. Cool, I can port some of my tests over to that. Cheers for the tip!

Steven Archibald on September 23, 2012 at 7:00 am.

So what do I point the Studio at if I’m running embedded in memory? The url, “localhost:8080″ doesn’t seem to work…

My browser keeps showing “connecting….”

அபூ அரீஜ் on November 29, 2012 at 1:31 am.

EmbeddableDocuemntStore works okay for unit testing but sucks at integration / frontend testing. This is a good solution!

அபூ அரீஜ் on November 29, 2012 at 3:45 am.

Actually, my above comment is now proven to suck. I yet to find a nice and clean way to rollback / reset RavenDB (not using in memory verison) when performing FrontEnd test.

Alex on November 29, 2012 at 8:01 pm.

Nice solution, normally id use an EmbeddableDocumentStore but currently no async sessions are allowed on EmbeddableDocumentStore , which means to test anything that makes use of an async session i need to use this.

I also found i needed to force RavenDB to create the new database, maybe it was a difference in version?

using Raven.Client.Extensions;

store.Initialize();
store.DatabaseCommands.EnsureDatabaseExists(Store.DefaultDatabase);

Hariprasad on January 31, 2014 at 11:54 am.

HI-

I am using ravendb in my mvc application.

i want to write test cased for my controllers and relevant logic code classes.

i want to use code classes but testing cholud be done locally i mean to say for insertion/updation/deletion etc any CRUD operation should perform locally.

how should i do, please help me out (send me any app helps me ton)…….

Thanks In Advance,
Hari

Leave a Reply