Saturday, November 2, 2013

Testing RavenDB

Lately I've been doing some development with RavenDB.  It's my first venture in to a "NoSQL" database and I've found it quite enjoyable to work with once you get out of the "relational" mindset.  One of the areas where Raven really shines is how easy it is to test.  Rather than mock out the RavenDB document store, you can spin up an in-memory version of RavenDB server, testing everything from Raven on up.

I usually test with the SpecsFor framework.  When I spin up my test I just create a new RavenDB in-memory EmbeddableDocumentStore and test with it.  Below is the base class I use with SpecsFor to handle spinning up and tearing down a new in-memory instance of RavenDB.

namespace MyProject.Test.Helpers 
{ 
    public abstract class SpecsForRavenDb<T> : SpecsFor<T> where T : class 
    { 
        private IDocumentStore _store; 
        public IDocumentSession RavenSession { get; set; } 
 
        public override void SetupEachSpec() 
        { 
            _store = new EmbeddableDocumentStore 
                { 
                    RunInMemory = true 
                } 
                .Initialize(); 
 
            _store.Conventions.DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites;
            IndexCreation.CreateIndexes(typeof(MyProject.MyIndex).Assembly, _store);  
 
            RavenSession = _store.OpenSession(); 
             
            base.SetupEachSpec(); 
        } 
         
        protected override void ConfigureContainer(StructureMap.IContainer container) 
        { 
            container.Configure(cfg => cfg.For<IDocumentSession>().Use(RavenSession)); 
        } 
 
        protected override void AfterSpec() 
        { 
            base.AfterSpec(); 
            RavenSession.Dispose(); 
            _store.Dispose(); 
        } 
    } 
}

Line 16 tells Raven to wait for writes to complete before returning results, more on this in my next post.
Line 17 tells Raven to go find the assembly we are testing and create all the indexes defined in the assembly.

The rest handles spinning up and disposing of the store after each test. Happy testing!

3 comments:

  1. I was about to give up on SpecsFor with Raven - this is really helpful.

    ReplyDelete
  2. I needed to make an addition to this to get it working with queries against static indexes. Following an equivalent solution for using Machine.Fakes - http://stackoverflow.com/questions/15903595/using-machine-fakes-unit-testing-with-ravendb-embeddabledocumentstore. In summary, this uses the BeforeQueryExecuted method of an IDocumentQueryListener implementation to ensure WaitForNonStaleResults() is called with each query.

    ReplyDelete
    Replies
    1. That was going to be the topic of my next blog post, but I slacked on on finishing that. I'll have to get to work on that!

      Delete