It wouldn’t surprise me if nobody noticed, but I overhauled my NHibernate articles. They are now grouped together in one convenient location.
Maybe when I have time, I will write about all the things I was doing wrong and how I fixed them.
It wouldn’t surprise me if nobody noticed, but I overhauled my NHibernate articles. They are now grouped together in one convenient location.
Maybe when I have time, I will write about all the things I was doing wrong and how I fixed them.
I’m going for a record: internet’s longest blog post title. FNHAMASPDNMVC3CWNUM is the official acronym of this post.
This is the fourth article in a series on using Fluent NHibernate with auto mappings. This time, I will cover unit testing with NUnit and Moq. If you haven’t already, you might want to catch up:
You may be asking yourself, “What is unit testing and why would I want to do it?” If that’s the case, then you should read my previous article: What is unit testing? Dependency injection?
Here’s what the completed project will look like:
If you don’t see the solution at the top of the Solution Explorer, go to the Tools menu > Options. In the Options window, ensure “Show all settings” is checked, then go to Projects and Solutions on the left and check “Always show solution” on the right:
This time, you don’t need to create a new ASP.NET MVC 3 web application. Instead, open the solution from last time, right click on the solution at the top of the Solution Explorer and choose Add > New Project…:
Choose Visual C# Class Library as the project template and name it CastleFluentNHibernateMvc3.Tests. Once the project has been added to the solution, delete the Class1 class. Next, right click on the Tests project in the Solution Explorer and choose Manage NuGet Packages… Search the online gallery for NUnit and install it. Also, search for and install Moq.
Once the packages have been downloaded and installed, add a folder to the Tests project named Controllers, then add a class to the Controllers folder named HomeControllerTest. Make this class public and prepend it with the TestFixture attribute, like so:
[TestFixture] public class HomeControllerTest { }
Finally, we’re ready to write some tests!
Remember, a unit test typically covers a single unit of code. In the case of a MVC application, that means that each action and method deserves its own unit test. Depending on the complexity, some actions and methods deserve several unit tests. Because our application is so simple, however, our unit tests will be relatively simple as well. As you can tell from the previous step, we will be writing unit tests for the actions in our home controller, starting with the Index action. For convenience, here is the code:
public ActionResult Index() { storeRepository.BeginTransaction(); var stores = storeRepository.GetAll(); if ( stores == null || !stores.Any() ) { storeRepository.Rollback(); return View( "Error" ); } try { storeRepository.Commit(); return View( stores.ToList() ); } catch { storeRepository.Rollback(); return View( "Error" ); } }
We want to make sure that every time the Index action is called the store repository returns a list of stores and the action returns a view. Testing that the action returns a view is simple enough, so at first we might try something like this:
[Test] public void Index() { // Arrange var controller = new HomeController(); // Act var result = controller.Index(); // Assert Assert.IsInstanceOf<ViewResult>( result ); }
The first thing you’ll notice is that the Tests project requires a reference to CastleFluentNHibernateMvc3, as well as System.Web.Mvc. Once you’ve added these references, Visual Studio will display this compilation error:
'CastleFluentNHibernateMvc3.Controllers.HomeController' does not contain a constructor that takes 0 arguments
The reason we get this error is because we modified the home controller constructor last time to use dependency injection. We did this because we don’t want to use our real repository in our unit tests. Instead, we want to use a fake (or mock) repository. This is where Moq comes in handy, although it does require a little setup before we can use it. First, we need a field to store our fake repository in the HomeControllerTest class, which we need to reset after each test execution:
[TestFixture] public class HomeControllerTest { private Mock<IRepository<Store>> storeRepositoryMock; [SetUp] public void Init() { storeRepositoryMock = new Mock<IRepository<Store>>(); } // ... }
Now, we can pass this value to the home controller constructor in our unit test, exposing its mocked instance with Moq’s Object property:
[Test] public void Index() { // Arrange var controller = new HomeController( storeRepositoryMock.Object ); // Act var result = controller.Index(); // Assert Assert.IsInstanceOf<ViewResult>( result ); }
Eventually, we may end up with lots of injected dependencies in our home controller constructor, so I like to extract the constructor call to a separate method:
[Test] public void Index() { // Arrange var controller = GetHomeController(); // Act var result = controller.Index(); // Assert Assert.IsInstanceOf<ViewResult>( result ); } private HomeController GetHomeController() { return new HomeController( storeRepositoryMock.Object ); }
At this point, if we try running our application, we will get a nasty error. We can’t run a class library directly. There are two options for running NUnit tests:
Whichever option you choose, our test should pass with flying colors! Unfortunately, there’s a problem. We’ve made sure our action returns a view, but the view it’s returning is actually the Error view. We can verify this by debugging our test. In Visual Studio, go to Debug > Attach to process… find nunit-agent.exe (if you chose option one above) or VisualNUnitRunner.exe (if you chose option two) in the list of processes and click the Attach button.
Now, we can put a breakpoint in our test and take a closer look at our result. Sure enough, the ViewName is “Error”:
We could have caught this sooner by testing that the view is getting the right model. In this case, our view should be getting a list of stores as its model. We would test for that as follows:
[Test] public void Index() { // Arrange var controller = GetHomeController(); // Act var result = controller.Index(); // Assert Assert.IsInstanceOf<ViewResult>( result ); var view = (ViewResult)result; Assert.IsInstanceOf<List<Store>>( view.Model ); }
If we run our test again, it should fail. NUnit will display the following error:
CastleFluentNHibernateMvc3.Tests.Controllers.HomeControllerTest.Index: Expected: instance of <System.Collections.Generic.List`1[CastleFluentNHibernateMvc3.Models.Store]> But was: null
Let’s put a breakpoint in our home controller this time and find out what’s going on. Doing this, we can see that our store repository is not returning any stores. And why should it? Remember, it’s a fake repository! We have to tell our fake repository what to do when it’s queried for a list of stores. But before we do that, make a copy of the Index test and rename it to Index_NoStoresFound. With a little modification, this test can still be useful:
[Test] public void Index_NoStoresFound() { // Arrange var controller = GetHomeController(); // Act var result = controller.Index(); // Assert Assert.IsInstanceOf<ViewResult>( result ); var view = (ViewResult)result; Assert.AreEqual( "Error", view.ViewName ); }
Keeping this test will ensure that the Index action always returns the Error view when our store repository doesn’t return any stores. If this test ever fails (for instance, because the Index action returns the Index view), then something is wrong with our error handling.
Now, let’s fix our Index test. We can use Moq’s Setup method to tell Moq what to return when we ask it for a list of stores:
[Test] public void Index() { // Arrange var controller = GetHomeController(); var stores = new List<Store> { new Store() }; storeRepositoryMock.Setup( s => s.GetAll() ) .Returns( stores.AsQueryable() ) .Verifiable(); // Act var result = controller.Index(); // Assert storeRepositoryMock.Verify(); Assert.IsInstanceOf<ViewResult>( result ); var view = (ViewResult)result; Assert.IsInstanceOf<List<Store>>( view.Model ); }
Notice that we can return any list of stores we want, so long as we convert it to an IQueryable because that’s what Moq expects to get back from the GetAll method of our store repository.
That concludes my series on using Fluent NHibernate with auto mappings. As always, let me know if you have any questions or comments. Good luck!
Previously, I mentioned that dependency injection is important for unit testing. If you are unfamiliar with either of these concepts, then your eyes probably glossed over when you read that sentence. I’m sure you could find many articles that cover unit testing and dependency injection on the interwebs. However, since I try to be newbie friendly (i.e. I am a newbie), I’m going to try to explain – in layman’s terms – the basic ideas behind these concepts. This will also give me a chance to learn more by teaching, which is how I learn best.
NOTE: I won’t be discussing test-driven development here. Some beginners get unit testing and TDD confused, but TDD is a separate topic that deserves its own article at some point in the future.
If you’ve ever done any programming in any language, then you are already familiar with manual testing. You might call it “looking for bugs” or “checking your work,” but it all boils down to launching your software and using it. At first, manual testing is quick and easy. After creating an HTML page, for instance, you would open it in a browser to verify that it looks okay. If it doesn’t, you would have to adjust the HTML until it passes the test. If it does, you might create another page and repeat the process. After that, you would need to add links from each page to the other. Then, you would have to open each page in a browser to verify that the links on each page work.
Here’s what usually happens pretty quickly: you have several pages, each with links to several other pages. Then, without thinking through the ramifications, you change a file name. This tends to happen at the worst possible moments, like right after your pages go live. Of course, it’s possible to test every link on every page every time you make a change like that. But if you are working on a large project, it can become extremely time consuming. Wouldn’t it be nice if there was a way to test every link on every page automatically every time you make a change?
There is a way. It’s called unit testing, and – if implemented correctly – it will save you from breaking changes. The reason it’s called unit testing instead of automatic testing is because it normally involves testing a single unit of code (a method or an action) at a time. To be honest, I don’t have a clue how you would write a unit test for the above scenario – at least not if all we’re dealing with is simple HTML pages. Frameworks such as Zend for PHP and ASP.NET MVC for C# lend themselves to such cases, which is one reason why they’re so popular. Here’s how we might do it in C#:
public class MyTests { public void TestLinks() { // Arrange var links = GetAllLinks(); var numErrors = 0; // Act foreach (var link in links) { if (!TryLink( link )) { numErrors ++; } } // Assert Assert.AreEqual( 0, numErrors ); } }
Of course, the implementation of such a test will vary greatly depending on the framework. Arrange-Act-Assert is a common pattern for unit testing:
At the end of the TestLinks method above, we assert that the number of errors is equal to zero. If it’s not, then the test will fail, letting us know that a link is broken. Ideally, you would run this test after making any changes that could affect it. Most importantly, you would run it before committing those changes to source control.
Dependency injection is often associated with unit testing because it allows you to test a unit of code by passing in a fake implementation rather than a concrete object. The most obvious case where you would want use this is to test a unit of code that needs to save data to a database.
Imagine that, on your website, a user can sign up for an account. To do this, the user must fill out and submit a form, which inserts a record into the database. This is something that needs to be tested – extensively, in fact, if you are a good developer.
If you’re using a data layer such as NHibernate or Entity Framework, you don’t need to test that the data is inserted into the database correctly. Also, you don’t want to insert a bunch of dummy data into the database. Instead, you need to test that the form is submitted, that an account is created, and that the page is redirected. If the user forgets to fill out a required field on the form, the page should be redirected to an error page, or back to the same page so the user can try again.
Now, assume your user controller has an action called NewUser that handles the form submission. In ASP.NET MVC, it might look something like this:
public class UserController : Controller { [HttpPost] public ActionResult NewUser( User user ) { // Data validation goes here // ... // Create a new instance of the repository var db = new Database(); // Insert the record into the database db.Save( user ); // Redirect the user to the success page return Redirect( Success ); } }
Then, our unit test might look something like this:
public void TestNewUser() { // Arrange var controller = new UserController(); var user = new User { FirstName = "Dave", LastName = "Ryder", UserName = "BigMcLargeHuge1", Password = "12345" }; // Act var result = controller.NewUser( user ); // Assert Assert.AreEqual( "Success", result.RouteData["Action"] ); }
Running that test would insert the dummy data into the database, but we’re not interested in that part. What we’d rather do is skip that part and just test that the page is redirected to the right action. To do that, we need to pass a fake database to the home controller:
public void TestNewUser() { // Arrange var controller = new UserController( new Fake<Database>() ); var user = new User { FirstName = "Dave", LastName = "Ryder", UserName = "BigMcLargeHuge1", Password = "12345" }; // Act var result = controller.NewUser( user ); // Assert Assert.AreEqual( "Success", result.RouteData["Action"] ); }
Then, we would need to modify the constructor of our user controller to accept a parameter for the repository. In other words, we need to inject our dependency into the constructor. We also remove the instantiation of the database class from the NewUser action:
public class UserController : Controller { private readonly Database db; public UserController( Database db ) { this.db = db; } [HttpPost] public ActionResult NewUser( User user ) { // Data validation goes here // ... // Insert the record into the database db.Save( user ); // Redirect the user to the success page return Redirect( Success ); } }
Instead of saving the data, our fake implementation of the database class just pretends to save the data so we can go on testing the parts we care about.
Hopefully, now you get the basic ideas behind unit testing and dependency injection. As I mentioned before, my next article will cover using NUnit and Moq for unit testing an ASP.NET MVC 3 application with NHibernate and Castle Windsor already implemented.