Categories
Technical

Explains TDD Workflow with C# application using NUnit

I have explained Test Driven Development in my earlier article, here I’m summarizing it again.

What is Test Driven Development (TDD)?

  • This is test-first development approach.
  • First write the test code, then write minimal code to pass the test, run this test code might fails due to tests codes are written even before the development code. Need to enhance and refactor the development code to pass the test.

Test Driven Development (TDD) Workflow:

  1. Write Test Code
  2. Run the Test Code
  3. Check the failed Tests
  4. Make Development code to pass tests
  5. Repeat step b.

We will walkthrough by creating simple C# application with has some basic calculator functionality, we implement the development code with Unit Testing by following Test-Driven Development (TDD).

Step 1: Create new console application, here I have created new project named “MyFirstNUnitApplication”.

Step 2: Once new project created, add the NUnit pacakge to this project. To Add new package Right click on References -> Manage NuGet Packages…

This will open the new window, there under Browse Tab, search for NUnit package like below screenshot, Then Install the package by clicking on install button, make sure latest version chosen.

Once installation done, We should install NUnitTestAdapter package too, this will be required to identity the tests by Test Explorer of Visual Studio. So like above process install NUnit3TestAdapter pacakge too.

Now you are ready to write tests to your application.

I have created two new classes one for Tests and other for implementations. Here CalculatorTest.cs and Calculator.cs for tests and codes respectively.

//CalculatorTest.cs
namespace MyFirstNUnitApplication
{
    class CalculatorTest
    {
    }
}

//Calculator.cs
namespace MyFirstNUnitApplication
{
    class Calculator
    {
    }
}

Step 3: Now we must start to write tests for calculator application. Include the following namespace in CalculatorTest.cs

using NUnit.Framework;

First, start to write the test for Addition operation,

namespace MyFirstNUnitApplication
{
    [TestFixture]
    class CalculatorTest
    {
        [Test]
        public void AdditionTest()
        {
            int number1 = 10;
            int number2 = 20;
            Calculator calculator = new Calculator();
            Assert.That(number1 + number2, Is.EqualTo(calculator.Add(number1, number2))); 
        }
    }
}

Here written tests to initialize two number, then compare the addition of these two numbers with addition implementation method output. Both needs to be same to pass this test.

If we build the project, you will get the error, that says “Calculator does not contain the definition for ‘Add’”, this is because we haven’t implemented to implementation code for Addition yet. So now we should start write the implementation code to build the project.

namespace MyFirstNUnitApplication
{
    class Calculator
    {
        private int result;
        public int Add(int num1, int num2)
        {
            return this.result;
        }
    }
}

Added new method for Add which accept two arguments and return integer type. Now you can build the application.

Now, its time to run the tests and see the tests result.

Step 4: To Run the Tests, Need to open Test Explorer Window by Test -> Windows -> Test Explorer.

Now, Test Explorer window will open on left side, there you can find all tests which categorized by Test Fixtures.

To Run the Tests, you need to click on Run All – this will run all the tests. To run the specific Tests, you can right click on that test and choose “Run Selected Tests”, then run it. You can see the test result after test run completed. To see detailed run information by clicking on test method.

As expected, the test we written has failed. Because we haven’t done code logic to do addition in Add method. We just write the definition for Add method in Calculator class. So now we should write the logic to pass the test. Check the updated method.

public int Add(int num1, int num2)
{
    this.result = num1 + num2; //Logic to do addition
    return this.result;
}

Now Run the Test from Test Explorer. You see test will be passed this time.

We just implement to simple case by following Test Driven Development (TDD). Now we can refine the tests by adding all possible assertions and make all to pass by updating the implementation code logic. Since Addition is simple logic there will no further assertion required.

So now we introduce another test method for Divide in CalculateTests.cs

[Test]
public void DivideTest()
{
    int number1 = 20;
    int number2 = 5;
    Calculator calculator = new Calculator();
    Assert.That(number1/number2, Is.EqualTo(calculator.Divide(number1, number2)));
}

Write the logic to Divide two numbers.

public int Divide(int num1, int num2)
{
    this.result = num1/num2; //Logic to do division
    return this.result;
}

Let enhance the DivideTest by throwing exception when denominator is zero.

[Test]
public void DivideWithExceptionTest()
{
    int number1 = 10;
    int number2 = 0;
    Calculator calculator = new Calculator();
    Assert.Throws<DivideByZeroException>(() => calculator.Divide(number1, number2));
}

Run the Tests, since you are passing denominator as 0, implemented method by default return the exception as DivideByZeroException. Now we can enhance the assert by not accepting denominator greater than numerator.

[Test]
public void DivideWithGreaterDenominatorTest()
{
    int number1 = 10;
    int number2 = 20;
    Calculator calculator = new Calculator();
    Assert.Throws<DenominatorGreaterException>(() => calculator.Divide(number1, number2));
}

Create new Custom Exception Class in Calculator.cs,

public class DenominatorGreaterException : ApplicationException
{ }

Add logic to check denominator is less than numerator, if not, then throws the custom exception error.

public int Divide(int num1, int num2)
{
    if (num2 > num1)
        throw new DenominatorGreaterException();

    this.result = num1/num2; //Logic to do divide
    return this.result;
}

We can do the same workflow to implement code for Subtraction and Multiplication. I will update the complete tests, and implementation code for all these operations.

//CalculatorTest.cs
using System;
using NUnit.Framework;

namespace MyFirstNUnitApplication
{
    [TestFixture]
    class CalculatorTest
    {
        Calculator calculator;

        [SetUp]
        public void Initialize()
        {
            calculator = new Calculator();
        }

        [Test]
        public void AdditionTest()
        {
            int number1 = 10;
            int number2 = 20;

            Assert.That(number1 + number2, Is.EqualTo(calculator.Add(number1, number2)));

            //You can use Assert.AreEqual too to check above
            Assert.AreEqual(number1 + number2, calculator.Add(number1, number2));
        }

        [Test]
        public void SubtractionTest()
        {
            int number1 = 20;
            int number2 = 10;

            Assert.That(number1 - number2, Is.EqualTo(calculator.Subtraction(number1, number2)));

            //You can use Assert.AreEqual too to check above
            Assert.AreEqual(number1 - number2, calculator.Subtraction(number1, number2));
        }

        [Test]
        public void MultiplicationTest()
        {
            int number1 = 10;
            int number2 = 20;

            Assert.That(number1 * number2, Is.EqualTo(calculator.Multiply(number1, number2)));

            //You can use Assert.AreEqual too to check above
            Assert.AreEqual(number1 * number2, calculator.Multiply(number1, number2));
        }

        [Test]
        public void DivideTest()
        {
            int number1 = 20;
            int number2 = 5;

            Assert.That(number1/number2, Is.EqualTo(calculator.Divide(number1, number2)));

            //You can use Assert.AreEqual too to check above
            Assert.AreEqual(number1/number2, calculator.Divide(number1, number2));
        }

        [Test]
        public void DivideWithExceptionTest()
        {
            int number1 = 10;
            int number2 = 0;

            Assert.Throws<DivideByZeroException>(() => calculator.Divide(number1, number2));
        }

        [Test]
        public void DivideWithGreaterDenominatorTest()
        {
            int number1 = 10;
            int number2 = 20;

            Assert.Throws<DenominatorGreaterException>(() => calculator.Divide(number1, number2));
        }
    }
} 

Note: I have used SetUp attribute to initialize the Calculator object, so we can avoid initializing this object in each tests.

//Calculator.cs
using System;

namespace MyFirstNUnitApplication
{
    class Calculator
    {
        private int result;

        public int Add(int num1, int num2)
        {
            this.result = num1 + num2; //Logic to do addition
            return this.result;
        }

        public int Subtraction(int num1, int num2)
        {
            this.result = num1 - num2; //Logic to do subtraction
            return this.result;
        }

        public int Multiply(int num1, int num2)
        {
            this.result = num1 * num2; //Logic to do multiply
            return this.result;
        }

        public int Divide(int num1, int num2)
        {
            if (num2 > num1)
                throw new DenominatorGreaterException();

            this.result = num1/num2; //Logic to do division
            return this.result;
        }
    }

    public class DenominatorGreaterException : ApplicationException
    {

    }
}

Hope this article helps to learn how to write Unit Tests by following TDD workflow for simple calculator application.

Leave a Reply

Your email address will not be published. Required fields are marked *