The purpose of this appendix is to provide a brief overview of Mock Object Frameworks. Most classes that you want to test depend on multiple other classes. A Mock Object Framework makes it possible to isolate code so that it is testable.
You can use several popular Mock Object Frameworks with ASP.NET MVC including the following:
• Moq—An open source Mock Object Framework that is relatively new but already popular. The ASP.NET MVC used Moq. You can download Moq from http://code.google.com/p/moq.
• Rhino Mocks—The established open source Mock Object Framework. You can download Rhino Mocks from http://ayende.com/projects/rhinomocks/downloads.aspx.
• Typemock Isolator—A commercial Mock Object Framework. Very powerful. You can learn more about Typemock Isolator from the company website at www.typemock.com.
In this appendix, I focus on describing Moq. The advantage of using Moq is that it is easy to understand. However, after you investigate Moq, I strongly encourage you to explore the other Mock Object Frameworks because each of the Mock Frameworks has its own strengths and weaknesses.
The terminology that surrounds Mock Object Frameworks can be confusing. Here is a brief glossary of terms:
• Double—This is the generic term for any object that you use as a replacement for a production object.
• Stub—A stub is an object that you use in place of a production object to make it easier to test your code. For example, you might create a stub for a repository class to make it easier to test a service class. You can generate stubs with a Mock Object Framework.
• Mock—A mock is a class that you use to test the interaction between objects in an application. When you create a mock object, you specify expectations about how other objects interact with the mock object. If the other objects do not interact with the mock object in the way that you expect, the test fails.
• Fake—A simplified version of a real production object. For example, a repository class that interacts with an in-memory database instead of an actual database. A fake is not created with a Mock Object Framework.
You can create two main types of objects with a Mock Object Framework: stubs and mocks. A stub is an object that you create to make it easier to perform a test. If one object depends on another object, you can stub the second object to make it possible to test the first object.
A mock object, in contrast, tests the interaction of the objects in your application. You create a mock of a production object to verify that the production object is called in the way that you expect. For example, you might want to verify the expectation that your service layer calls a particular method in your repository layer. In that case, you can mock the repository layer to verify this interaction.
In this appendix (and this book), I focus on using Mock Object Frameworks to create stubs and not mocks.
This terminology is based on Gerard Meszaros’s terminology from his book xUnit Design Patterns: Refactoring Test Code. Also see the following two articles by Martin Fowler at http://martinfowler.com/bliki/TestDouble.html and http://martinfowler.com/articles/mocksArentStubs.html.
You can download Moq from the following location: http://code.google.com/p/moq.
After you download Moq, make sure that you unblock the archive by right-clicking the file, selecting Properties, and clicking the Unblock button (see Figure C.1).
If you don’t unblock Moq, Visual Studio generates mysterious security errors when you try to use Moq in your test project.
Before you can use Moq in a test project, you need to add a reference to the Moq assembly. Follow these steps:
After you complete these steps, use the Moq framework in your test project.
Imagine that you want to create a Movie database application. Imagine, furthermore, that you have followed proper design patterns and divided your application logic into separate classes in which each class has a single responsibility.
You create a controller class, a service class, and a repository class. The controller class contains your controller logic, the service class contains your validation logic, and the repository class contains your data access logic.
The controller class is contained in Listing C.1.
And, the service class is contained in Listing C.2.
And, the repository class is contained in Listing C.3.
Now, imagine that you want to test the service class. You want to verify that if you pass a movie with a missing title to the service class Create()
method, the method returns the value false.
Unfortunately, you can’t just create the service class in your test code because it depends on two other classes. The service class depends on an instance of the ModelStateDictionary
class and an instance of the MovieRepository
class. You can see these dependencies by looking at the constructor for the service class.
The ModelStateDictionary
class does not present a problem. The ModelStateDictionary
is just a specialized collection class. We can simply create a new instance of this class in our test code.
The MovieRepository
class, on the other hand, does present a problem. We don’t want to create an instance of the actual MovieRepository
class because the actual class interacts with a database. We need some way of creating a double for the actual MovieRepository
class for the purposes of our test code.
As an alternative to stubbing the MovieRepository
class, we could fake the MovieRepository
class. We could fake the MovieRepository
class by implementing the IMovieRepository
interface with a class that interacts with an in-memory database instead of the actual database. We explore this option in Chapter 5, “Understanding Models.”
We can use the Moq framework to quickly and easily create a stub for our MovieRepository
class. The test in Listing C.4 illustrates how you can generate a stub from the IMovieRepository
interface.
In Listing C.4, the stub for the MovieRepository
class is created with this line of code:
(C#)
var repositoryStub = new Mock<IMovieRepository>();
(VB)
Dim repositoryStub As New Mock(Of IMovieRepository)()
Notice that the stub for the repository class is created from an interface: The stub is created from the IMovieRepository
interface. (You also could create the stub from an abstract class.)
The repositoryStub
variable does not represent the class that implements the IMovieRepository
interface. You must use the expression repositoryStub.Object
to get to the double for the MovieRepository
. The responsitoryStub.Object
class is the class that has the ListMovies()
and CreateMovie()
methods.
In the previous section, you learned how you can test the Movie
service class by creating a stub for the Movie
repository class. By taking advantage of a Mock Object Framework, we isolated the Movie
service class from the Movie
repository class.
In this section, you learn how to return values from a stub object. In some situations, you need to make a stub class behave in a particular way to perform a test on the actual class being tested.
For example, imagine that you want to test the Movie
controller class. This class is dependent on the Movie
service class. To test the Movie
class, we need to do more than simply stub the Movie
service class. We need to fake values returned from calling methods on the Movie
service class.
We want to test the controller logic in the Movie
controller Create()
action. The Create()
action does one of two things depending on the value returned from calling the MovieService.CreateMovie()
method. If CreateMovie()
returns false—there is a validation error—then the Create()
action should redisplay the form for creating a movie. On the other hand, if CreateMovie()
returns true, then the Create()
action should return a RedirectToAction result.
To test the Movie
controller, we need to fake the value returned by the Movie
service CreateMovie()
method. We need to fake the value returned by the Movie
service to fully test the Movie
controller.
The two tests in Listing C.5 illustrate how you can fake the value returned by the CreateMovie()
method.
The CreateWithBadMovieReturnsView()
test verifies that when the Movie
service CreateMovie()
method returns false, the Movie
controller returns a view result. The CreateWithGoodMovieReturnsRedirect()
test verifies that when the Movie
service CreateMovie()
method returns true, the Movie
controller returns a redirect to route result. (The RedirectToAction()
method returns a RedirectToRouteResult
.)
The following line of code causes the Movie
service CreateMovie()
method to return the value true:
(C#)
serviceStub.Setup(s => s.CreateMovie(It.IsAny<Movie>())).Returns(true);
(VB)
serviceStub.Setup(Function(s) s.CreateMovie(It.IsAny(Of Movie)())).Returns(True)
When any movie parameter is passed to the CreateMovie()
method, the CreateMovie()
method returns the value true.
18.221.158.222