Improving Code Confidence - Unit Testing

Setting up the Project

Nice and simple to get started with this – right click on your solution file, and choose add > new project. In the dialog popup, select Test on the left, pick the unit test project and name it. I am creating a unit test project per layer, and I will separate out my different types of tests into different projects, so I am calling my test project CMCS.BaseBlogSystem.Services.UnitTests.

When you click ok, this will create a project with the appropriate reference to Microsoft.VisualStudio.QualityTools.UnitTestFramework. Delete the sample class it creates. To make my tests easy to navigate, I am structuring it in the same way as the project it is testing. For example, I have a Messaging folder with a BaseServiceResponse class, so I am creating a Messaging folder with a BaseServiceResponseTests class (named slightly differently to avoid name conflicts.

 

Writing Your First Test

So now we have a unit test project ready to go. Unit Tests should be small, quick, documentation for the code, easy to read and understand. Do not be tempted to test more than one thing in an unit test. In my example, I am just testing if I have null lists in my class, does the ResponseType return my expected value (Ok)? How many tests you write for you code is up to you, and will be dependent on the complexity. In the simple example I have taken, I could write 7 or 8 tests to comprehensively test this small simple bit of code. For some, this may be overkill, but you should try and make sure that you cover at least the “happy path” and common “sad paths” with your unit testing.

In my class, I have my first unit test:

namespace CMCS.BaseBlogSystem.Services.UnitTests.Messaging

{

    [TestClass]

    public class BaseServiceResponseTests

    {

        [TestMethod]

        public void ResponseTypeReturnsOkIfValidationListsAreNull()

        {

            //Arrange

            BaseServiceResponse response = new BaseServiceResponse();

            response.ValidationErrors = null;

            response.ValidationWarnings = null;

 

            //Act

            var result = response.ResponseType;

 

            //Assert

            Assert.IsTrue(result == Helpers.MessageHelper.Statuses.OK);

        }

 

 

    }

}

If I run this test from the test explorer (Test > Windows > Test Explorer) I can ensure it passes.

I am going to add a few more unit tests, I will gradually add tests to my existing code, but any new functionality will be written in Test Driven Development. This uses the red, green, refactor method. I.e. you write a test to describe the functionality you want. Run the test, and the test fails (red) as you haven’t yet written the functionality. Next, write the bare minimum code to get the test to pass (green). Once you have a passing test you have confidence in your code. The next step is to refactor the code to ensure it meets your code quality standards and improve the maintainability.

Code Coverage

To help you find areas of code not covered by unit tests, you can use the code coverage tool in Visual Studio. From the Test menu, choose Analyze Code Coverage > All Tests.

This will analyse your project, and output the results in the Code Coverage Results pane.

As I only has a couple of unit tests, my coverage is only 0.62%, but I will aim to increase that. You can drill down using the arrows to the left of the projects to get a better idea of your coverage.

What’s the point?

I quickly came to realise to comprehensively test a piece of code, I could easily write 10 times the amount of code in the tests themselves. So what’s the point? The four points for me that are most valuable are:

  • Code documentation. The unit tests provide some of the most comprehensive code documentation you can get. It is also completely maintainable, as the tests should be changed first if there is a change in functionality (to fail), and the code then updated to get the test green again. Keeping the documentation up to date becomes part of the developer workflow, rather than having to remember to update some mark down or a wiki that sits outside the process.

 

  • Inadvertent breakages. This is especially true for projects where the functionality is changing or being added to at pace. Unit tests provide confidence that you haven’t broken any of the other code (which is a common occurrence in brownfield applications due to tight coupling)

 

  • Fast feedback. Possibly the most valuable. Rather than having to publish my application to a server and test via the front end (very time consuming due to the number of possible codepaths you are testing as you are now testing your entire stack), you can run your unit tests as soon as you’ve finished tweaking, and fix anything and re run them and fix anything and re run them….. many many times in the time it would take you to deploy and test.

 

  • Clearer feedback. If I test the full stack, debugging an error is much more time consuming because it is more difficult to tell where the error occurred (you are testing many more lines of code and probably a database). As unit tests only test a small number of lines of code, fixing an issue is much easier as you know exactly where to look.


Tagged: ASP.NET, .Net, Testing, Unit Testing,
Categorised: Application Lifecycle Management,
By:
On: