Products

Solutions

Resources

Partners

Community

About

New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.


Adventures in Testing - 3 - Dummies, Fakes, Stubs and Mocks

This article is cross-posted from my personal blog.

One of the tenets of Unit Testing is that in order to test a piece of code we often need to create some alternate implementation of one or more of the Interfaces involved in a test.  This concept is generally called a Test Double.  However there are many types of Test Double, and there is some degree of confusion about the types of doubles used.

In this installment of “Adventures in Testing” I will attempt to clarify the types of Test Doubles.

Dummies

Dummies are the simplest type of test double – these are objects that are needed to be passed around but they don’t actually do anything so they can have a very simple implementation.  Usually they are required just to fill a parameter list in a method call.

An example would be a test for the following constructor -

Figure 1: A method that can be tested using a Dummy Test Double

   1:  Public Sub New(ByVal createView As ICreateVocabularyView, _
   2:                 ByVal vocabularyController As IVocabularyController, _
   3:                 ByVal scopeTypeController As IScopeTypeController)
   4:      MyBase.New(createView)
   5:      Arg.NotNull("vocabularyController", vocabularyController)
   6:      Arg.NotNull("scopeTypeController", scopeTypeController)
   7:   
   8:      '.....
   9:  End Sub

In this example the constructor takes three parameters.  If we are testing that the constructor throws an Exception if one of the arguments are null, we need to ensure that the other parameters are not null.  So for example our test to ensure that the Constructor throws an Exception if the VocabularyController is null might look like this.

Figure 2: A test using a Dummy Test Double

   1:  public void Constructor_Requires_Non_Null_VocabularyController()
   2:  {
   3:      //Arrange
   4:      DummyCreateVocabularyView view = new DummyCreateVocabularyView();
   5:      DummyScopeTypeController scopeTypeController = new DummyScopeTypeController();
   6:   
   7:      //Act
   8:      CreateVocabularyPresenter presenter = new CreateVocabularyPresenter(view, 
   9:                                                      null, 
  10:                                                      scopeTypeController);
  11:      
  12:      //.....
  13:  }

We don’t care about the implementation of the first (ICreateVocabularyView) or third (IScopeTypeController) interfaces in this test, we just need them to be non-null – all we care about is that the constructor throws if the second parameter is null.

Fakes

The other three types of Test Doubles all have some form of implementation as we are testing some part of the Interface in question.

Fake objects usually have full working implementations, but they use some shortcut, and are not of production quality.  An example of a Fake object would be when testing the business layer of an application, where we create an in-memory Fake DataService class to simulate the data access, and allow us to test the business layer methods, without requiring a database to be set up.

Stubs

Stubs provide canned answers to calls made during a test, and usually don’t respond at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.

Mocks

Mocks are usually dynamically created by a mocking framework – (in DotNetNuke we use Moq as the mocking framework). Mock objects are preprogrammed with expectations which form a specification of the calls they are expected to receive (see Figure 3)

Figure 3; An example of using a Mock Object

   1:          public void VocabularyListPresenter_On_Add_Redirects_To_CreateVocabulary()
   2:          {
   3:              // Arrange
   4:              Mock mockController = new Mock();
   5:              Mock view = new Mock();
   6:              view.Setup(v => v.Model).Returns(new VocabularyListModel());
   7:   
   8:              Mock httpContext = new Mock();
   9:              Mock httpResponse = new Mock();
  10:              httpContext.Setup(h => h.Response).Returns(httpResponse.Object);
  11:   
  12:              VocabularyListPresenter presenter = new VocabularyListPresenter(view.Object, mockController.Object)
  13:              {
  14:                  HttpContext = httpContext.Object,
  15:                  ModuleId = Constants.MODULE_ValidId,
  16:                  TabId = Constants.TAB_ValidId
  17:              };
  18:   
  19:              // Act (Raise the AddVocabulary Event)
  20:              view.Raise(v => v.AddVocabulary += null, EventArgs.Empty);
  21:   
  22:              // Assert
  23:              httpResponse.Verify(r => r.Redirect(Globals.NavigateURL(Constants.TAB_ValidId,
  24:                                                  "CreateVocabulary",
  25:                                                  String.Format("mid={0}", Constants.MODULE_ValidId))));
  26:          }

In Figure 3 we are using 4 separate Mock objects, but lets focus on the two mocks created in lines 8 and 9.  In line 8 we create a Mock HttpContextBase using Moq’s Mock class, and in line 9 we create a Mock HttpResponseBase.  Just creating the Mock does nothing more that create in memory an object that can respond to an interface, or (as in this case) an abstract base class.

In line 10 we setup the Mock HttpContextBase, so that when it receives a call to its Response property it will return the object represented by the Mock HttpResponse object.

In line 15 we set HttpContext property of the presenter to this Mock HttpContextBase.

Now we have set up our test so we can test the view’s AdddVocabulary method (see Figure 4), which is designed to redirect to a new page when the AddVocabulary button is clicked.

Figure 4: The AddVocabulary method that Figure 3 is testing

   1:  Public Sub AddVocabulary(ByVal sender As Object, ByVal e As EventArgs)
   2:      Response.Redirect(NavigateURL(TabId, _
   3:                                    "CreateVocabulary", _
   4:                                    String.Format("mid={0}", ModuleId)))
   5:  End Sub

So, in line 21 we raise the AddVocabulary event by calling the Raise method of the Mock view.  This will cause the presenter’s event handler to be triggered and in line 24 we verify that this caused our Mock Response object to have its Redirect method called, with the expected url.

Note: This example is based on the new Model-View-Presenter code which will be included in DotNetNuke 5.3 and provides a new Module Development Framework that provides full testability.

One of the advantages of a Mocking Framework like Moq is that it can be used to replace most types of Test Double.  For example we can write the test using Dummy objects in Figure 2 to use Mocks (Figure 5).

Figure 5: The example in Figure 2 rewritten using Moq instead of Dummies

   1:  public void Constructor_Requires_Non_Null_VocabularyController()
   2:  {
   3:      //Arrange
   4:      Mock view = new Mock();
   5:      Mock scopeTypeController = new Mock();
   6:   
   7:      //Act, Assert
   8:      CreateVocabularyPresenter presenter = new CreateVocabularyPresenter(view.Object, 
   9:                                                          v, 
  10:                                                          scopeTypeController.Object);
  11:   
  12:      //..
  13:  }

Comments

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out