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.


DNN Unit/Integration Testing – Part 3

Introduction

This is the third article to guide those who would like to contribute to DNN Platform on how to write tests. In this article, I will expand on the previous articles (Part 1 and Part 2) and show you how to start adding new test features. I will base the tests on a real code that was contributed by some community members.

 

Why Integration Tests

Due to the way some parts of the DNN code were written over the years it might not be possible to write unit tests as it needs a huge amount of stubbing and mocking, even, in some cases, it might not be possible at all. Therefore, we need to write integration tests which operate on an actual installed DNN site and a SQL server database.

DNN has created a small framework to facilitate in this task by providing utilities and helper classes to makes it easy to create users and login as these users and call WEB API methods, etc. These library helpers are packaged as a NuGet package and published to the public feed of DNN packages here

Besides, integration tests usually have no mocks or stubs to write which makes writing them a bit simpler in this area but have to deal with different concerns of its own such as sessions and others which makes the tests larger when it comes to coding. They only need to setup the proper values of the tested site; such as, the URL to the site, the connection sting to the database, any app-settings related to the site. These are usually added to the “App.config” file of the test project.

 

Adding Your First Integration Test(s)

In the following discussion I will show you how to add integration tests to the existing Platform code base. I will walk you through creating a few tests for the “MemberDirectoryController.cs” WEB API methods by sending requests, validating the responses, and checking the results in the database. Unlike the tests in part 2, there is no Jira and Github pull request associated with these practice tests.

To perform WEB API requests, you either need to have the source code to find out what are the parameters names and type that are passed with the request or use some tools to inspect the wire messages that go on the network. The browser tools (which are available by pressing F12 key) are there for your help. Or you can use standalone tools; such as, Fiddler, but these are outside the scope of this article. For this tutorial, I will assume you are testing a code that you have written or already have access to so that you know the internals of the tests.

Let’s have a look at the member directory WEB API service in the file “MemberDirectoryController.cs”.  In this file there are many API methods utilizing the GET and POST verbs. Let’s pick a few that can be the base for this demo. I’ll assume the following scenario:

  • Create user 1 and user 2 using provided helpers in the framework

  • User 1 logs in and sends a friend request to user 2.

  • We check the database contains the friend request.

  • User 2 logs in and accepts the friendship request.

  • Again we check the database to validate this.

For this purpose we will be using the following methods:

 

[HttpPost]

public HttpResponseMessage AddFriend(FriendDTO postData)

[HttpPost]

public HttpResponseMessage AcceptFriend(FriendDTO postData)

 

So, we start by:

  • navigating to “DotNetNuke.Tests.Integration”
  • selects the “Tests” folder under it
  • add a new folder called “MemberDirectory”
  • add a class under it called “MemberDirectoryTests.cs”
  • modify the new class to inherit from the “IntegrationTestBase” class (this is the integration framework class that simplifies many things for writing the tests)
  • create an empty positive test method and add the NUnit necessary attributes to the code

The final result should look something like this:

VS Solution

using DNN.Integration.Test.Framework;

using NUnit.Framework;

namespace DotNetNuke.Tests.Integration.Tests.MemberDirectory

{

    [TestFixture]

    public class MemberDirectoryTests : IntegrationTestBase

    {

        [Test]

        public void Send_And_Accept_Friendship_Requests_Positive_Test()

        {

            Assert.Fail();

        }

    }

}

 

Identifying the WEP API endpoint

To know what the endpoints for the WEB API methods is, we need to look into the “MemberDirectoryServiceRouteMapper.cs” which contains the following code:

       mapRouteManager.MapHttpRoute(

        "MemberDirectory",

        "default",

        "{controller}/{action}",

        new[] { "DotNetNuke.Modules.MemberDirectory.Services" });

 

And the file “MemberDirectoryController.cs” contains:

public class MemberDirectoryController : DnnApiController

[HttpPost]

public HttpResponseMessage AddFriend(FriendDTO postData)

 

From the above we can formulate the endpoint to call the add friend method will be:

POST http://<site-url>/api/MemberDirectory/MemberDirectory/AddFriend

 

In the above, the first “MemberDirectory” is the MapHttpRoute’s first argument (in the first code snippet) while the second one is the controller name without the “Controller” text part (in the second code snippet), and the last part of the endpoint “AddFriend” is the method we are calling. All these parts are highlighted in the code above.

 

Adding Integration Test Code

Note: before proceeding you need to make sure you updated the test project’s “App.config” file values to match the site you are testing against. 

We start our coding by creating the two users we need to use for the tests. To achieve this, we utilize the available helpers in the integration testing framework. I advise you to get yourself familiar with these helpers as they will reduce the code amount, the time, and the effort to add tests.

The test contains many actions and assertion that need some explanation which I added as comments in the code itself. Here is the full file:

using System;

using DNN.Integration.Test.Framework;

using DNN.Integration.Test.Framework.Helpers;

using NUnit.Framework;

namespace DotNetNuke.Tests.Integration.Tests.MemberDirectory

{

    [TestFixture]

    public class MemberDirectoryTests : IntegrationTestBase

    {

        private const string AddFriendQuery = "/api/MemberDirectory/MemberDirectory/AddFriend";

        private const string AcceptFriendQuery = "/api/InternalServices/RelationshipService/AcceptFriend";

        [Test]

        public void Send_And_Accept_Friendship_Requests_Positive_Test()

        {

            int userId1, fileId1, userId2, fileId2;

            string username1, username2;

            // create two test users - will create a user with name "testuser" padded with 4

            // random numeric digits and obtain a connection (session) for the new user.

            // the connector/session will have the user logged in when successful.

            var connector1 = WebApiTestHelper.PrepareNewUser(out userId1, out username1, out fileId1);

            var connector2 = WebApiTestHelper.PrepareNewUser(out userId2, out username2, out fileId2);

            Console.WriteLine(@"Test users => {0} and {1}", connector1.UserName, connector2.UserName);

            // make sure there are no pending notifications so we can check for the add-friend notification

            DatabaseHelper.ExecuteNonQuery("DELETE FROM {objectQualifier}CoreMessaging_Messages");

            var notificationsCount = DatabaseHelper.ExecuteScalar<int>(

                "SELECT COUNT(*) FROM {objectQualifier}CoreMessaging_Messages");

            Assert.AreEqual(0, notificationsCount);

            // Send Add friend request from user 1 to user 2. We must add the proper headers which

            // we obtain from calling GetRequestHeaders for the members directory page.

            // Note that without the proper request headers, the call might not be successful.

            var response1 = connector1.PostJson(AddFriendQuery, new { friendId = userId2 },

                WebApiTestHelper.GetRequestHeaders("Member Directory"));

            // Make sure the request succeeded

            Assert.IsTrue(response1.IsSuccessStatusCode);

            // Get friend request from database and check there is one

            var notificationId = DatabaseHelper.ExecuteScalar<int>(

                "SELECT TOP 1 MessageID FROM {objectQualifier}CoreMessaging_Messages WHERE SenderUserID="

                + userId1);

            Assert.Greater(notificationId, 0);

            // let user 2 approve the request

            connector2.PostJson(AcceptFriendQuery, new { NotificationId = notificationId });

            // make sure the notfication wa sprocessed and removed

            notificationsCount = DatabaseHelper.ExecuteScalar<int>(

                "SELECT COUNT(*) FROM {objectQualifier}CoreMessaging_Messages");

            Assert.AreEqual(0, notificationsCount);

        }

    }

}

 

Notice how there is a mix of API calls to the actual web site and at the same time we check the database to assert some values were added to, or removed from, the database. Also, notice the use of the object qualifies of the database “{objectQualifier}”. If you let these out, your tests will pass on the sites which do not use qualifiers, but if the site is using it, then the tests will surely fail.

I will not add negative tests in this tutorial, and will leave it as an exercise for you to see what happens if you send a request to non-existing user.

 

Submitting Your Tests

As in the previous article, you have written these tests then what next? It is time now for committing your changes and pushing them to the repository then creating a pull request.

 

Summary

I just touched the basics of adding integration tests in DNN. The existing tests in the Platform repository have many more examples for you to learn from. So, don’t hesitate to have a look and send me any questions you like as comments to this series of blogs.

Comments

There are currently no comments, be the first to post one.

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