Occasionally I’ll find myself in a position where I need to unit test some code that has internals that are set privately at runtime. Today I found myself in such a position, and I used some reflection to solve the need. This isn’t something I like to do often; I’d prefer to have code that is testable without reflection, but sometimes the path of least resistance can be ok.
RavenController
The RavenDB documentation has an example of a controller that can be used for managing RavenDB sessions for your derived controllers in ASP.NET MVC. I’ve taken that example and made it a little better, in that I can pass in the store through the constructor from the derived controller, which itself was injected. Here’s what that looks like:
public abstract class RavenController : Controller
{
private readonly IDocumentStore documentStore;
protected IDocumentSession session { get; private set; }
protected RavenController(IDocumentStore documentStore)
{
this.documentStore = documentStore;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
this.session = this.documentStore.OpenSession();
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.IsChildAction)
{
return;
}
using (this.session)
{
if (filterContext.Exception != null)
{
return;
}
if (this.Session != null)
{
this.session.SaveChanges();
}
}
}
}
...
public class FooController : RavenController
{
public FooController(IDocumentStore documentStore)
: base(documentStore)
{
}
public ActionResult Bar()
{
//do some stuff with the session here
}
...
}
No Framework Help
Now, when it comes time to unit test a controller such as this, it’s a little challenging. One nice thing with RavenDB is you can ‘new’ up FooController, and pass it a RavenDB embedded in-memory store to test with:
var store = new EmbeddableDocumentStore()
{
RunInMemory = true,
};
store.Initialize();
using (var entriesController = new EntriesController(store))
{
...
}
The problem is that once you try to call your action directly off this object, you won’t have the benefit of the OnActionExecuting/OnActionExecuted execution ahead/behind your code. Therefor, the session in this case will be null, and the test will fail with a NullReferenceException.
It IS possible to write a whole bunch of ceremony to get this mocked and wired up, but in my opinion it’s not worth the extra 10-20 lines of code just for that.
Dirty Reflection Tricks
I want to set that session property’s private setter. Here’s how I can do that with reflection:
typeof(FooController).BaseType
.GetProperty("session", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(fooControllerInstance, session, null);
If that makes you feel gross, good, it’s supposed to. But it gets the job done, and you can get on with testing FooController’s action with your embedded in-memory test store without concerning yourself too much with the RavenController infrastructure.