简体   繁体   中英

ASP.NET MVC, RavenDb and Unit Testing

I'm just getting started with RavenDB and I like it so far. I am however stuck on how I should unit test controller actions that interact with it.

All the questions/articles I have found like this one: Unit testing RavenDb queries tell me I should use RavenDB in memory rather than mock it away but I cannot find a solid example of how this is done.

For example I have a controller action to add an employee to the database (yes, it's overly simplified but I don't want to complicate the issue)

public class EmployeesController : Controller
{

  IDocumentStore _documentStore;
  private IDocumentSession _session;

  public EmployeesController(IDocumentStore documentStore)
  {
    this._documentStore = documentStore;

  }

  protected override void OnActionExecuting(ActionExecutingContext filterContext)
  {
    _session = _documentStore.OpenSession("StaffDirectory");
  }

  protected override void OnActionExecuted(ActionExecutedContext filterContext)
  {
      if (_session != null && filterContext.Exception == null) {
        _session.SaveChanges();
        _session.Dispose();
    }
  }

  [HttpGet]
  public ViewResult Create()
  {
    return View();
  }

  [HttpPost]
  public RedirectToRouteResult Create(Employee emp)
  {
    ValidateModel(emp);
    _session.Store(emp);
    return RedirectToAction("Index");
  }

How can I verify what was added to the database in a unit test? Does anyone have any examples of unit tests involving RavenDb in MVC applications?

I'm using MSTest if that matters but I'm happy to try and translate tests from other frameworks.

Thanks.

EDIT

Ok, my test initialise creates the document store that is injected into the controller constructor, but when I run my test the OnActionExecuting event doesn't run so there is no session to use and the test fails with a null reference exception.

[TestClass]
public class EmployeesControllerTests
{
  IDocumentStore _store;

  [TestInitialize]
  public void InitialiseTest()
  {
    _store = new EmbeddableDocumentStore
    {
      RunInMemory = true
    };
    _store.Initialize();
  }

  [TestMethod]
  public void CreateInsertsANewEmployeeIntoTheDocumentStore()
  {
    Employee newEmp = new Employee() { FirstName = "Test", Surname = "User" };

    var target = new EmployeesController(_store);
    ControllerUtilities.SetUpControllerContext(target, "testUser", "Test User", null);

    RedirectToRouteResult actual = target.Create(newEmp);
    Assert.AreEqual("Index", actual.RouteName);

    // verify employee was successfully added to the database.
  }
}

What am I missing? How do I get the session created to use in the test?

After you've run your unit test, just assert that there is a new doc in the database and that it has the right fields set.

var newDoc = session.Load<T>(docId)

or

var docs = session.Query<T>.Where(....).ToList();

RavenDB in-memory mode is there so that you don't have to mock it out, you just do the following:

  • Open a new in-memory embedded doc store (with no data)
  • If needed insert any data your unit test needs to run
  • RUN the unit test
  • Look at the data in the in-memory store and see if it has been updated correctly

Update If you want a full sample, take a look at how the RacoonBlog code does it, this is the code running Ayende's blog . See these 2 files:

How can I verify what was added to the database in a unit test?

You don't. We don't test such things in unit tests. This is a responsibility for integration tests, NOT unit testing.

If you want to unit test classes, which depend on some external source (like your db), mock the database access.

EDIT:

To correct some mentioned mistakes, I'll quote definition from MSDN (however all other resources agree with that):

The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect.

Without mocking you are ignoring the basic principles of Unit testing - isolation and testing the smallest piece possible. Unit test need to be persistent-ignorant and shouldn't be relying on some external class. What if the db changes over time? Rewrite all tests, even though the functionality stays exactly the same?

COME ON. You can give me -1 how many times you want, but that won't make you right.

As that thread you linked to mentioned use the EmbeddableDocumentStore by embedding RavenDB.

Here's how to set that up: http://msdn.microsoft.com/en-us/magazine/hh547101.aspx

Here's how to use the repository pattern with raven, so you can test easily: http://novuscraft.com/blog/ravendb-and-the-repository-pattern

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM