Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 435
Nick Avatar asked May 02 '12 21:05

Nick


People also ask

How to unit test MVC application in Visual Studio?

Each unit is tested separately before integrating them into modules to test the interfaces between modules. Let’s take a look at a simple example of unit testing in which we create a new ASP.NET MVC application with Unit Testing. Step 1 − Open the Visual Studio and click File → New → Project menu option. A new Project dialog opens.

Can I run a unit test on a web site?

The unit tests won’t run yet, but you can run the web site to verify data is getting returned to the Index method. Don’t confuse running the site with running a unit test. Think about what takes less time, running the site, logging in, navigating to the page and then verifying the data or running the unit test.

How do I know if a test passes in MVC?

If the test passes, you'll see the Test Results window in Figure 2. Figure 01: Run All Tests in Solution ( Click to view full-size image) Figure 02: Success! ( Click to view full-size image) An MVC controller passes data to a view by using something called View Data.

How do I get Started with unit testing?

Abstract: Get started with unit testing using a simple ASP.NET MVC application. You’ll see how to setup the test and remove the database from the testing process. Gardeners understand the problems that insects can cause to their plants. Entire gardens can be destroyed in short time.


2 Answers

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:

  • BlogConfigBehavior.cs
  • RaccoonControllerTests.cs
like image 129
Matt Warren Avatar answered Sep 29 '22 16:09

Matt Warren


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.

like image 38
walther Avatar answered Sep 29 '22 14:09

walther