ASP.NET MVCModel-View-Controller (MVC) is a design pattern that separates a web application into three layers: model, view and controller. Model refers to the data layer; usually it's the layer that interacts directly the data. Basically it's a layer that talks to the database. View, on the other hand, is the layer that manages the presentation. The presentation layer here can be anything: it can be a form, or HTML, or XML or any other presentation layout. The controller manages the interaction between the model and the view; it's the brain of the application.
One reason why MVC design pattern is so popular over the years, is because it encourages the separation of concern, namely, different types of functionalities are encoded in different modules. MVC differs from the traditional ASP.NET Webform in that it's easier to change layers. Take for examples if your application needs to run on both web and mobile phone, you don't have to rewrite the whole application; you just have to change the presentation layer, namely the view and keep the controller and model layer intact. MVC also encourages unit testing and promotes a more modular approach to web development. No wonder it generated much excitement when Microsoft announced the ASP.NET MVC project.
Unit Testing and AAA SyntaxEveryone has heard about unit testing, and everyone knows by heart that unit testing is important. But the fact is that not many developers actually do it in their production code. Such a wide gap between theoretical understanding and practical doing is indeed astounding, and depressing.
The gap can be attributed partly to the way unit testing is presented in the textbooks and the way unit test that need to be done in the real world. The unit tests, in books, or in blogs, or in tutorials are often applied on simple or trivial examples. But in the real world, code is often messy, different concerns are hopelessly tangled together, and it's often untestable because it has too many fragile dependencies. So when a novice, after reading an introductory test-driven development(TDD) book wants to apply unit test in his code, he will often find that he doesn't know how to deal it and how to write test.
Mocks and stubs are artifacts that we introduce to workaround the external dependencies problems. The idea is that instead of really calling the external modules that rely on your indeterminate, lousy internet connection, you are fakingthe calls and returning a pre-determined objects. So you are using mocks and stubs to make sure that your method receives a pre-determined input from external modules and at the end of the test, you make sure that proper external dependencies are invoked.
AAA syntax stands for Arrange, Act and Assert. First you arrange, i.e., setup your test, then you act, i.e., call the method under test, and finally assert,i.e., verify that the output is correct, or to check that specific methods, with correct parameters are called. It performs the same function of mocks.
Personally I prefer AAA syntax over the traditional mocks and stubs, because it's simpler to understand and shorter to write.
Separation of Test ConcernSeparation of concern is a well-known design pattern in software development. What is less well-known, but no less equally utilized is the separation of testconcern.
To make things easier, and maybe for organizational purpose, developers who write tests will often structure their test code in parallel with their production code. This kind of parallel setup is great for testing and debugging purpose. However, a complete separation of testing layers is not possible without mocking and stubbing.
The concept of unit testing is to test the code in isolation. But our code can never be truly isolation from one another, so there is always a possibility of an innocuous change in other layers will break your test code. Not that your code is wrong, though, but just that the external dependencies return a value that you don't expect, and hence create a false positive.
The whole idea of mocks and stubs, and AAA syntax, is to make sure that you can test what you want to test, that your test results won't be influenced by what's going on in other layers.
A RedditClone ApplicationHere is a simple Reddit clone application, RedditClone. It has little or no HTML design, and the missing of key features ( such as vote up/down, karma system) are glaring. But I think this application is enough demonstrate how to unit test an ASP.NET MVC application using AAA syntax. Here is a screenshot of the application, click to see full size.
Model classesThe model class has the following repository classes:
Basically, both RedditMembershipProvider and ItemFactory are the classes that deal with the databases directly. They are where all the ORM logics and business rules will reside in. As far the controllers are concerned, it has to deal with those classes, instead of messing with the ORMs and SQL queries themselves.
Controller classesThe controller classes consist of the following controllers.
Note that they are just a direct map of their underlying model classes.
Unit Testing ModelUnit testing the model is the easiest of all; one just has to access a test database ( with properly populated initial data, of course) to test the Model classes logic. There are no mocks involved, because there are nothing to mock anyway. Take for example, the following two methods test whether the function ValidateUser is really returning true if the username and password match, or return false if the username and password don't match.
Unit Testing ControllerController, on the other hand, is a bit more difficult to test. The reason for this is that it is dependent on the model as the input, thus it is best if we could control the model's output directly to really test the controller logic, instead of have to calibrate the input to the model so that the model returns the desired output, so that the controller's action could be properly tested.
Let's assume that for AccountController, we have the following rules
- If login successful, authentication cookies should be set, and the page should be redirected to Item/Main method.
- If the login fails, then the same page should be displayed, along with the error message
- Due to a bug in the underlying ORM, one cannot call the data layer if the username is empty
Let's see how one can write the tests using Typemock.
The first thing to note is that the actions of controller requires output from Model, in this case, the output of
This, in return, would be dependent on the database content, so we should mock away this dependencies, and fake the appropriate returns to test the controller.
We also need to make sure that the output is what we expected by using a combination of Assert and Isolate.Verify. Here's the setup of AccountControllerTest:
Note that to unit test the controller, we keep the AccountController as a real object, and we are faking the two key properties, namely, the controller.Provider( the class to handle DAL) and the controller.FormsAutho( the class to handle the setting of cookies). This test pattern is the most commonly used pattern ( at least by me) in unit testing because it has the highest test coverage/test code ratio. And here's the 3 tests that cover the above rules:
The reader can verify himself that the above tests are indeed a faithful representation of the given rules.
What is interesting is the way we handle the dependencies on DAL. In this case we have to mock away ValidateUser and return the output that we want. Also, at the end of the test, we also assert that whether the ValidateUser is or is not called, depending on the specs.
Also note the call ReturnRecursiveFake automatically returns all the objects and the properties and the sub properties of them appropriate fake values so that you don't have to create mocks manually. This simplifies the setup coding a lot.
The source code for the complete application, along with the test code, can be found here. There are more examples on how to use the AAA to segmentize the layers for unit testing. As usual, comments and feedbacks are welcome.
RemarksUsing mock is especially important in software development. A lot of times we are hindered in our progress because the dependencies we are relied on "are not done yet". Thus mock can help us to write and test our code even though the underlying module is not completed yet. Mocks and stubs are also very helpful in keeping the test layer separated.
AAA syntax does away with the concepts of stubs and mocks, and clarifies the intend of the test code and makes writing and reading tests more fun. Working with ASP.NET MVC, with Typemock's AAA syntax is a joyous experience.
AcknowledgementSpecial thanks to Gil for reading the first draft of this article
This article was written by Soon Hui Ngu
Soon Hui is a software engineer living and working in Malaysia