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.


Creating Testable Modules - ViewLinks

This article is cross-posted from my personal blog

In the previous article in this blog series on creating testable modules, I introduced the sample DotNetNuke module that we will build – Links MVP.  This is a simpler version of the core DotNetNuke Links module.  In this article we will build our first tests.

Test Driven Development – TDD

In the first article in this blog series I discussed a number of core concepts including the concept of Test Driven Development (TDD).  In this development paradigm you write the test first, and your tests become the Specification.  More specifically the process can be summarized as follows (from Test-Driven Development, By Example – Kent Beck)

  1. Write a test
  2. Run all tests – and see the new test fail
  3. Make a little change – to make the test pass
  4. Run all tests and see them all succeed
  5. Refactor to remove duplication
  6. Repeat

I don’t necessarily intend to do the whole project in this way, as the focus of this blog series is not Test Driven Module Development per se, but creating Testable Modules.  But it is an interesting experiment.

Our First Test

The first test we will write is shown in Listing 1.  This test is designed to simulate that when the ViewLinks view is given a valid ModuleId (ie a ModuleId for a Links module that has some links defined) the View will display all the Links.

Listing 1 – The First Test

   1:  [TestMethod]
   2:  public void View_Should_Display_All_Links_When_ModuleId_Is_Valid()
   3:  {
   4:      //First Create the Mock View and a Mock Repository
   5:      MockLinksView view = new MockLinksView();
   6:      MockLinksRepository repository = new MockLinksRepository();
   7:   
   8:      //Create the Presenter
   9:      LinksViewPresenter presenter = new LinksViewPresenter(view, repository);
  10:   
  11:      //Set the Views Module Id
  12:      view.ModuleId = MockHelper.ValidModuleId;
  13:   
  14:      //Call the presenters OnViewLoaded method to simulate the Page Load
  15:      presenter.OnViewLoaded();
  16:   
  17:      //Assert that the View displays two Links
  18:      Assert.AreEqual(2, view.Links.Count);
  19:  }

So lets look at this test.  In lines 4 and 5 we create two Mock objects a MockLinksView and a MockLinksRepository.  In line 9 we then pass both of these Mock objects in the constructor to create a LinksViewPresenter.  We use Mock objects here as we are testing the Presenter.

In line 12 we set the View’s ModuleId property to a “valid” Id.  As with the HelloWorld example we call the presenters OnViewLoaded method and then we assert that the number of links in the view’s Links property is 2.

In this test we have two Mock objects and one object that is part of the LinksMVP project – the LinksViewPresenter.  Listing 2 shows this LinksViewPresenter class.

Listing 2 – The LinksViewPresenter Class

   1:  public class LinksViewPresenter
   2:  {
   3:      ILinksView view;
   4:      ILinksRepository repository;
   5:   
   6:      public LinksViewPresenter(ILinksView view, ILinksRepository repository)
   7:      {
   8:          this.view = view;
   9:          this.repository = repository;
  10:      }
  11:   
  12:      public void OnViewLoaded()
  13:      {
  14:          view.Links = repository.GetLinks(view.ModuleId);
  15:      }
  16:  }

The smart readers will have already noticed something different from the Hello World example, the addition of the IRepository interface.  Otherwise this class is similar to the HelloWorldPresenter. 

The Repository Pattern

There are two strategies that can be used in the Business Layer, for handling the logic involved with creating, retrieving, updating and deleting (CRUD) the business objects.  In the first strategy, the business objects have methods which handle the logic, in the second a separate class, called a Repository, focuses on the business logic keeping the objects themselves lightweight.

DotNetNuke developers will recognize this pattern as the Controller classes are essentially “Repositories”.  In this blog series I will use the term Repository – to clearly differentiate from the Controller found in the MVC pattern or the MVP Supervising Controller pattern.

So ILinksRepository is obviously an interface that describes this logic.  We use an interface so we can create Mock versions of the interface (see Listing 3).  It contains a single method GetLinks, which retrieves a List of Link objects.

Listing 3 – The ILinksRepository Interface

   1:  public interface ILinksRepository
   2:  {
   3:      List GetLinks(int moduleId);
   4:  }

In our test we create a MockLinksRepository (see Listing 4).  We do this because the test is designed to just test the Presenter.  We will write a test for the Repository in a later article.

Listing 4 – TheMockLinksRepository class’s GetLinks method

   1:  public List GetLinks(int moduleId)
   2:  {
   3:      List links;
   4:      switch (moduleId)
   5:      {
   6:          case MockHelper.ValidModuleId:
   7:              //Valid Module Id - Create a List with two Links
   8:              links = new List();
   9:              links.Add(MockHelper.CreateLink(1, moduleId));
  10:              links.Add(MockHelper.CreateLink(2, moduleId));
  11:              return links;
  12:          default:
  13:              //Any other Module Id - return an empty List
  14:              links = new List();
  15:              return links;
  16:      }
  17:  }

This method takes a moduleId and returns a List of links (created using a helper function, Listing 5), as long as the moduleId is valid.

Listing 5 – The MockHelper.CreateLink method

   1:  public static Link CreateLink(int linkId, int moduleId)
   2:  {
   3:      //Create a Link with the linkId and moduleid provided
   4:      Link link = new Link()
   5:      {
   6:          LinkId = linkId,
   7:          ModuleId = moduleId,
   8:      };
   9:      return link;
  10:  }

Note that I am using the new syntax in C# 3.0 to create a Link object (see Listing 6) and set its two properties (LinkId and ModuleId).  The two Links are added to a List and returned (Listing 4 – line 11).

Listing 6 – The Link Class

   1:  public class Link : ILink
   2:  {
   3:      private int linkId;
   4:      private int moduleId;
   5:   
   6:      public int LinkId
   7:      {
   8:          get { return linkId; }
   9:          set { linkId = value; }
  10:      }
  11:   
  12:      public int ModuleId
  13:      {
  14:          get { return moduleId; }
  15:          set { moduleId = value; }
  16:      }
  17:  }

The View

Finally we will look at the View.  Our test requires us to set the ModuleId and then check the Links property.  Listing 7 shows the ILinksView interface and Listing 8 shows the MockLinksView.

Listing 7 – The ILinksView Interface

   1:  public interface ILinksView
   2:  {
   3:      int ModuleId { get; set; }
   4:      List Links { set; }
   5:  }

Listing 8 – The MockLinksView Class

   1:  class MockLinksView : ILinksView
   2:  {
   3:      private List links;
   4:      private int moduleId;
   5:   
   6:      public List Links
   7:      {
   8:          get { return links; }
   9:          set { links = value; }
  10:      }
  11:   
  12:      public int ModuleId
  13:      {
  14:          get { return moduleId; }
  15:          set { moduleId = value; }
  16:      }
  17:  }

We should now have everything we need to run the tests.  If we run the test we will get a green light, as we did add two links in our Mock Repository class.

Our Second Test

So now we have a passing test, we need to write a second test (Listing 9).

Listing 9 – The Second Test

   1:  [TestMethod]
   2:  public void View_Should_Display_No_Links_When_ModuleId_Is_Not_Valid()
   3:  {
   4:      //First Create the Mock View and a Mock Repository
   5:      MockLinksView view = new MockLinksView();
   6:      MockLinksRepository repository = new MockLinksRepository();
   7:   
   8:      //Create the Presnter
   9:      ViewLinksPresenter presenter = new ViewLinksPresenter(view, repository);
  10:   
  11:      //Set the Views Module Id
  12:      view.ModuleId = MockHelper.InValidModuleId;
  13:   
  14:      //Call the presenters OnViewLoaded method to simulate the Page Load
  15:      presenter.OnViewLoaded();
  16:   
  17:      //Assert that the View displays 0 Links
  18:      Assert.AreEqual(0, view.Links.Count);
  19:  }

The second test simulates the case where we pass an invalid Module Id (a ModuleId which has no links defined).  In this test we check that the Links property of the View is empty.  We now have two green lights and our code coverage is pretty good already.

Figure 1 – Code Coverage from our Two Tests

LinksMVPCodeCoverage1

We have good code coverage because we have only written code that we need.  This is one of the advantages of the TDD process as it encourages you to only do enough to pass the test.  In this case the only area of the project we haven’t got code coverage of are the getters of the Link class.

Updating our First Test

We know what the values of the two links we passed to the LinksView are, as we create them in the Mock Repository class, so we can update our first test (Listing 10), so we can get 100% code coverage (Figure 2)

Listing 10 – The Modified First Test

   1:  [TestMethod]
   2:  public void View_Should_Display_All_Links_When_ModuleId_Is_Valid()
   3:  {
   4:      //Set the Views Module Id
   5:      view.ModuleId = MockHelper.ValidModuleId;
   6:   
   7:      //Call the presenters OnViewLoaded method to simulate the Page Load
   8:      presenter.OnViewLoaded();
   9:   
  10:      //Assert that the View displays two Links
  11:      Assert.AreEqual(2, view.Links.Count);
  12:   
  13:      //Assert that the first link has a LinkId of 1 and a Module Id of ValidModuleId
  14:      Assert.AreEqual(1, view.Links[0].LinkId);
  15:      Assert.AreEqual(MockHelper.ValidModuleId, view.Links[0].ModuleId);
  16:  }

Note that I have now moved the code that is common to both tests to the Test class’s constructor (This is an example of the Refactor phase of the TDD cycle)

Figure 2 – Updated Code Coverage from our Two Tests

LinksMVPCodeCoverage2

So we now know that our Presenter works – it retrieves the Links and passes them to the View.  Our Link model is incomplete, we only have a LinkId property and a ModuleId property, so that is not very useful, but it is a fairly trivial task to add more properties to the object, update the MockHelper.CreateLink method and update our test to assert that the values are correct, and finally to run the tests to make sure everything still works.

Note: It should be noted here that some developers who use TDD say that you don’t need to test simple getters and setters, but it is quite easy to make typos in the simplest of code, so I have included assertions for each property.

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