NUnit Test MVC Controller

We want to test the controller in an MVC application. We want to pass values in and be able to catch the response.

The response from our controller will tell us if the test has passed or failed. If you build the application well then all these tests should pass once they get the right response.

Previously On Serversncode

All source code for the project can be found here

Getting started.

To Recap our project

  • NUnit_Demo.Web
  • Nunit_Demo.Data
  • Nunit_Demo.Tests
  • Nunit_Demo.Web is the MVC application.

NunitDemo.Data is a class library that get's called by the HomeController in the NunitDemo.Web application. This pretends to talk to a database for the purpose of these samples.

Nunit_Demo.Tests is where the tests take place and run from.

To test an MVC Controller we need to add MVC to our Test project. We can do this in NuGet

PM> Install-Package Microsoft.AspNet.Mvc

for more information

Now to our test setup.

We are going to test saving a user. In our Nunit_Demo.Data we add a new class called User

public class User
{
    public string Email_VC { get; set; }
    public string FirstName_VC { get; set; }
    public string LastName_VC { get; set; }
    public int Number_IN { get; set; }
}

Next we add a new class called UserQueries

    public int InsertUser(string sFirstName, string sLastName, string sEmail, int iNumber)
    {
        int iUserID = 0;



        // Create our user 
        User _user = new User
        {
            Email_VC = sEmail,
            FirstName_VC = sFirstName,
            LastName_VC = sLastName,
            Number_IN = iNumber
        };

        // Add code here to save user to the database.
        iUserID = 1;

        return iUserID;
    }

    public Boolean DeleteUser(int iUserId)
    {
        Boolean bSuccess = false;

        // Here we add code to delete the user from the database.
        bSuccess = true;

        return bSuccess;
    }

Our UserQueries has two methods. InsertUser and DeleteUser as before to keep things clean I've pretended to hit a database of some kind.

Now into our Nunit_Demo.Web Project we open the HomeController and add a method called SaveUser

    //Save User method to demonstrate Unit testing of parameters
    public ActionResult SaveUser(string firstname, string lastname, string email, int number)
    {
        UserQueries UQ = new UserQueries();

        int iUserId = 0;
        Boolean bValid = true;

        // Validate User Input
        // Do we have a first name
        bValid = (firstname == "" ? false : true);

        // Do we have a last name
        bValid = (lastname == "" ? false : true);

        // Do we have an email
        bValid = (email == "" ? false : true);




        // If Valid Save User
        if (bValid)
        {
            iUserId = UQ.InsertUser(firstname, lastname, email, number);
        }


        if (iUserId == 0)
        {
            return Redirect("/saveuser?message=MESSAGEHERE");
        }
        else
        {
            return Redirect("/UserAdded");
        }

This is a simple ActionResult method for MVC. It takes the parameters and then uses a redirect to pass you onto the next page or return you back to the save user page.

In this case if the parameters are missing it will set bValid to false and send you into a redirect to saveuser with a message.

Testing a controller

So back into our Nunit_Demo.Tests

We create a class UserTest

[TestFixture]
public class UserTest

Our first test is the easy one, Create a test user and get the UserID from the response of the controller.

    [Test]
    public void CreateUserTest()
    {
        string sFirstName = "James";
        string sLastName = "Test";
        string sEmail = "test@serversncode.com";
        int iNumber = 7;
        Boolean bTestSuccess = false;
        string sMessage = "";


        HomeController _homeController = new HomeController();

        ActionResult result = _homeController.SaveUser(sFirstName, sLastName, sEmail, iNumber);

        var actResult = (RedirectResult)result;
        int iUserID = 0;

        // User Added successfully
        if (actResult.Url.StartsWith("/UserAdded?id="))
        {
            // We remove the URL and pull the ID for the new user we just created
            string sURL = actResult.Url.Replace("/UserAdded?id=", "");

            iUserID = Convert.ToInt32(sURL);

            // If the user ID not 0
            if (iUserID != 0)
            {
                bTestSuccess = true;
                sMessage = "User Saved ok";
            }
            else
            {
                // If UserId is 0 something went wrong and the User didn't save ok, 
                // So the test fails.
                bTestSuccess = false;
                sMessage = "User Save failed";
            }
        }
        else
        {
            // If the result URL is Save user
            string sURL = actResult.Url.Replace("/saveuser?message=", "");



            // The test has passed if this code is hit.
            bTestSuccess = true;
            sMessage = "";
        }


        // Test fails if bTestSuccess is false;
        Assert.IsTrue(bTestSuccess, sMessage);

    }

I have a bit of code here so lets work trough it.

        string sFirstName = "James";
        string sLastName = "Test";
        string sEmail = "test@serversncode.com";
        int iNumber = 7;
        Boolean bTestSuccess = false;
        string sMessage = "";

We setup our parameters and values for the testing.

        HomeController _homeController = new HomeController();

        ActionResult result = _homeController.SaveUser(sFirstName, sLastName, sEmail, iNumber);

We then call our Home Controller.

NOTE: there are a number of ways to do this but I like this way, it's clean and easy to maintain over time.

        var actResult = (RedirectResult)result;
        int iUserID = 0;

Our SaveUser method responds with an ActionResult. We know for this that we are getting a RedirectResult as a response so we can cast that into our actResult.

        if (actResult.Url.StartsWith("/UserAdded?id="))

We then check our actResult.URL method if it starts with /UserAdded we know that the user was added successfully. Because that is the response we are expecting.

            string sURL = actResult.Url.Replace("/UserAdded?id=", "");

            iUserID = Convert.ToInt32(sURL);

Here I simply strip the url of the expected characters and leave myself with an int that I can easily convert.

            if (iUserID != 0)
            {
                bTestSuccess = true;
                sMessage = "User Saved ok";
            }
            else
            {
                // If UserId is 0 something went wrong and the User didn't save ok, 
                // So the test fails.
                bTestSuccess = false;
                sMessage = "User Save failed";
            }

We check to see is the userID 0 or not. If it is 0 we know this test has failed because this test should have saved a user to the system.

If iUseID is not 0 then we have a successful test.

        else
        {
            // If the result URL is Save user
            string sURL = actResult.Url.Replace("/saveuser?message=", "");



            // The test has passed if this code is hit.
            bTestSuccess = true;
            sMessage = "";
        }

Our SaveUser controller can send two redirect responses. One is the saved. and the user is a saveuser with a message.

If in this case our controller responds with /saveuser the test has succeeded, because if something has gone wrong and it hasn't allowed the user to move on. The system failed but sent the user back to the first screen.

NOTE: This isn't always the case and you might consider this a fail but that's open for you to decide.

        Assert.IsTrue(bTestSuccess, sMessage);

Our test will pass if the bTestSuccess flag is true. It's a simple yes / no test.

Ok so lets make the test do a bit more. Our controller validates the user input so it checks to see if we pass in the firstname, lastname or email.

We create a new test and set the firstname and lastname parameters to ""

        string sFirstName = "";
        string sLastName = "";
        string sEmail = "test@serversncode.com";
        int iNumber = 7;
        Boolean bTestSuccess = false;
        string sMessage = "";


        HomeController _homeController = new HomeController();

        ActionResult result = _homeController.SaveUser(sFirstName, sLastName, sEmail, iNumber);

        var actResult = (RedirectResult)result;
        int iUserID = 0;

The top part of this test is the same as our last test.

        // User Added successfully
        if (actResult.Url.StartsWith("/UserAdded?id="))
        {
            // With this test we are not expecting to be here. 
            // If we are then something went wrong in our validation.
            bTestSuccess = false;
            sMessage = "User Save failed";
        }

This is were it gets interesting. Because of our validation in the controller we should not get here. Our redirect should not send the user added. If it does the test has failed.

        else
        {
            // If the result URL is Save user
            sMessage = actResult.Url.Replace("/saveuser?message=", "");

            // The test has passed if this code is hit.
            bTestSuccess = true;
        }

We should come here with a message of some kind. The test has passed. Our controller validated the parameters found the missing values and sent it back.

About these tests

These tests are very simple and I think in most cases tests should be simple. Like anything in programming we can make things as complicated or as simple as we want. Really it depends if you want to punish yourself in 4 weeks time. If you don't then keep it simple.

I will be going deeper into the rabbit hole of making tests more complex but overall if I can I keep my tests clean and simple.

By doing that and sticking to it the tests are easy to maintain as the code base grows it can be maintained easier. There is less reason to remove tests or ignore them, which happens when tests are too complex or over the top.

We want to test the controller in an MVC application. We want to pass values in and be able to catch the response. The response from our controller will tell us if the test has passed or failed. If you build the application well then all these tests should pass…

Read More

API Testing with Postman

Postman

Postman is a powerful API Testing tool, I've been using it for a while to test the API's I've been creating. It presents you with a friendly GUI for constructing requests and reading responses.

The people behind Postman also offer an add-on package called Jetpacks, which includes some automation tools and, most crucially, a Javascript testing library but the basic use of Postman is free.

Get PostMan on windows it runs as a chrome app.

Postman

The URL is the first thing that you would be setting for a request. Clicking on the URL params button will open up the key-value editor for entering URL parameters.

This allows you to build the request to send.

When you send a request it will display the response from the API

Methods

Postman allows a number of API methods for all your needs.

Changing the method is straightforward. Just select the method from the select control. The request body editor area will change depending on whether the method can have a body attached to it or not.

Request Body

Postman lets you send almost any kind of HTTP request.

Form-Data

multipart/form-data is the default encoding a web form uses to transfer data. This simulates filling a form on a website, and submitting it. The form-data editor lets you set key/value pairs (using the key-value editor) for your data. You can attach files to a key as well.

urlencoded

This encoding is the same as the one used in URL parameters. You just need to enter key/value pairs and Postman will encode the keys and values properly.

raw

A raw request can contain anything. Postman doesn't touch the string entered in the raw editor except replacing environment variables. Whatever you put in the text area gets sent with the request. The raw editor lets you set the formatting type along with the correct header that you should send with the raw body. You can set the Content-Type header manually as well. Normally, you would be sending XML or JSON data here.

binary

binary data allows you to send things which you can not enter in Postman. For example, image, audio or video files. You can send text files as well. As mentioned earlier in the form-data section, you would have to reattach a file if you are loading a request through the history or the collection.

Response

An API response consists of the body, headers and the status code. Postman organizes body and headers in different tabs. The status code with the time taken for the API call is displayed next to the tabs. You can hover over the status code to get more details about the code.

The Postman body tab gives you several tools to help you make sense of things quickly. The body can be viewed in one of three views - pretty, raw, and preview.

Pretty

The pretty mode formats JSON or XML responses so that they are easier to look at. Nobody wants to scroll through a minified single line JSON response looking for that elusive string.

Raw

The raw view is just a big text area with the response body. It can help to tell whether your response is minified or not.

Preview

The preview tab renders the response in a sandboxed iframe. Some web frameworks by default return HTML errors and the preview mode is especially helpful there. Due to iframe sandbox restrictions, Javascript and images are disabled in the iframe.

Postman Postman is a powerful API Testing tool, I've been using it for a while to test the API's I've been creating. It presents you with a friendly GUI for constructing requests and reading responses. The people behind Postman also offer an add-on package called Jetpacks, which includes some automation…

Read More