Writing model tests for Neo4j


So over the last few weeks, I’ve been playing around with the idea of moving My.Stocked.Kitchen’s recipe and ingredient database over to a Neo4j graph database from the original MySQL relational database. My belief is that a graph DB better suits the relationship structure of recipes and ingredients (and their similar ingredients) than a traditional relational DB.

I’ve been playing around with using ActiveNode (neo4jrb/neo4j) instead of ActiveRecord, but the problem was that my models are dependent on some gems for extra capabilities such as Friendly_id and Sunspot.

Since I wasn’t able to find a sunspot_neo4j-like gem, I began working on my own. I modeled it after the original sunspot_mongoid implementation and I was very impressed with how easy and straight-forward it seemed. You can see below the code that was required to get it working:

You can find the whole source here: sunspot_neo4j

But an interesting thing happened when I finished the original implementation of sunspot_neo4j. I wanted to ensure I had some specs written that verified everything was working (supposedly that makes you a “good” developer), but wasn’t able to find a good library to use that would start up a local Neo4j instance just for the lifetime of tests. Looked like it was time to start writing a second gem designed specifically for creating specs that have a real dependency on an existing Neo4j server.

The end result ended up being me writing the neo4j_test_server gem.

For sunspot_neo4j, I had a few testing requirements that I needed this gem to provide:

  • Manage a locally running Neo4j instance (including download/startup/shutdown)
  • Hooks into Rspec for stopping, cleaning, and starting the instance during test execution
  • Support tests that require different versions of Neo4j
  • Needed to be scoped to only particular tests. I didn’t want ALL of the specs to manage a running Neo4j instance. Just the ones where I couldn’t use mocks.

And so that’s just what neo4j_test_server provides. If you follow the README on the project’s site, you’ll see exactly how to get started.

For sunspot_neo4j, I ended up with something like the following:

I required all of the necessary files within my spec_helper.rb, but you’ll notice that I add the neo4j: true tag to the tests that require a running local Neo4j instance.

When run, the neo4j_test_server gem will download, configure, and startup a Neo4j instance that your tests can connect to. I have an example/dummy Rails app setup in the spec folder that is initialized during test startup so that I can properly test the actual models a user of the gem would have in their Rails application. To me, this keeps the specs pretty clean since I don’t have to include any test models directly in the specs themselves.

I have also added some logic to the gem using Ruby’s “at_exit” method so that when the specs finish, any running Neo4j servers will automatically be shutdown. The idea was to put the system back into state it was in prior to launching the tests.

The cool thing I’m able to do with this gem is configure tests to automatically run against different versions of Neo4j without the tests having to deal too much with cleaning up after themselves. The gem takes care of all of that. If you look at the test block at line 25 above, you can see that I can simply list the versions of Neo4j that sunspot_neo4j supports and run all of my tests. Easy-peasy.

In the end, I was pretty happy with how both neo4j_test_server and sunsport_neo4j turned out. Both work for the use cases I wanted them to cover and each has rspec tests that help me verify the “correctness” of the gems as work continues on both.

Try them out for yourselves and let me know what you think.