Testing Framework

Now, let's talk about MSTest, its a unit testing framework that allows us to create and run the tests
We can use MSTest testing framework for writing our unit/integration/e2e(UI tests)

Before we jump into details of MSTest, we will talk about different types of tests and the testing pyramid

Types of tests


Unit
Testing smallest units of code

Integration
Units of code are integrated with each other and tested

E2E
Verify system meets requirements, testing the entire system from end to end

Test Pyramid



Above image is self-explanatory, so one should write as many unit tests as he can for testing application

As you climb the pyramid, test execution time increases that is unit tests are faster than UI
Also, the brittleness of test increases that is UI test is most brittle compared to the unit test.


I have created a simple project to calculate tax based on the price of an item, we will walk through the code and then write some unit tests wherein I will explain some functionalities of MSTest framework

Check below code

namespace MSTestDemo
{
    public class TaxManager
    {
        private int price;
        public TaxManager(int price)
        {
            this.price = price;
        }
        public int CalcualteTax()
        {
            if (price < 10000)
                return price / 100;
            else
                return price / 1000;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            TaxManager taxManager = new TaxManager(1000);
            int tax = taxManager.CalcualteTax();
            Console.WriteLine("Calculated Tax: " + tax.ToString());
            Console.Read();
        }
    }
}


Here we have a TaxManager class which calculates the tax based on the price of an item.
If the price is less than 10000 then price/100 is the tax amount else price/1000 is the tax amount.

Self-explanatory code, now we will add unit tests for CalculateTax method, to do so right click anywhere from the method and click "create unit tests"

This will open the below window



Here you can see the Test framework is MSTest
It will create a new project for our tests

Click ok and it created below test template for us to start writing our tests

namespace MSTestDemo.Tests
{
    [TestClass()]
    public class TaxManagerTests
    {
        [TestMethod()]
        public void CalcualteTaxTest()
        {
            Assert.Fail();
        }
    }
}

Here TestClass and TestMethod are attributes used by MSTest framework to identify tests


Now we will add a test for calculating the tax when the amount is less than 10000, we expect the tax to be amount/100

namespace MSTestDemo.Tests
{
    [TestClass()]
    public class TaxManagerTests
    {
        [TestMethod()]
        public void CalcualteTaxTest_When_Price_Less_Than_10000()
        {
            //Arrange
            int price = 5000;
            TaxManager taxManager = new TaxManager(price);
            int expectedTax = price/ 100;
 
            //Act
            int actualTax = taxManager.CalcualteTax();
 
            //Assert
            Assert.AreEqual(expectedTax, actualTax);
 
        }
    }
}

Every test you write should follow Arrange Act Assert Pattern (AAA)

Arrange- Prepare the test data
Act- Perform the action
Assert- Verify the expected outcome

Here in our tests above we calculated our expected tax and called the calculate tax method and finally we asserted that the actual and expected tax values match

To run the tests open the test explorer and right click the test and click "run selected tests"
You can run all the test for the class by right click on the class and click "run selected tests"



We will add another test for calculating the tax when the amount is greater than 10000, we expect the tax to be amount/1000

[TestMethod()]
       public void CalcualteTaxTest_When_Price_greater_Than_10000()
       {
           //Arrange
           int price = 50000;
           TaxManager taxManager = new TaxManager(price);
           int expectedTax = price / 1000;
 
           //Act
           int actualTax = taxManager.CalcualteTax();
 
           //Assert
           Assert.AreEqual(expectedTax, actualTax);
 
       }

Run the test and you can see results are green(Passing).

Now, we will add a failing test case.

Suppose we set price as negative then we expect the code to throw Argument Exception, currently, we have not handled this case.

We will write the test case first which will fail
       [TestMethod()]
       [ExpectedException(typeof(ArgumentException))]
       public void CalcualteTaxTest_When_Price_is_negative()
       {
           //Arrange
           int price = -1;
           TaxManager taxManager = new TaxManager(price);
           int expectedTax = price / 100;
           var expectedTaxNew = Math.Round
                               (Convert.ToDecimal(expectedTax));
 
           //Act
           decimal actualTax = taxManager.CalcualteTax();
 
          
 
       }
Here you can notice that we do not have an assertion. We are using ExpectedException attribute to specify which type of exception we are expecting.

So if the code return ArgumentException then the test will pass else it will fail.

After running the test, we can see it fails with below error message

Message: Test method did not throw expected exception System.ArgumentException. 


Now we will handle this case in our code to fix this issue, check below

namespace MSTestDemo
{
    public class TaxManager
    {
        private int price;
        public TaxManager(int price)
        {
            this.price = price;
        }
        public decimal CalcualteTax()
        {
            if (price < 0)
                throw new ArgumentException("Price not valid");
 
 
            if (price < 10000)
                return price / 100;
            else
                return price / 1000;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            TaxManager taxManager = new TaxManager(1000);
            decimal tax = taxManager.CalcualteTax();
            Console.WriteLine("Calculated Tax: " + tax.ToString());
            Console.Read();
        }
    }
}


So before calculating the tax now we check if the value is less than zero if that's the case then we throw ArgumentException.

Re-run our failing test, now you would find that it is passing.

Now we will talk about some attributes of the MSTest framework

Test Initialize - This method will run before each test , you can add code to prepare for testing here.
Test Cleanup - This method will run after each test case, you can add code to release resources here.

[TestInitialize]
      public  void testInitialize()
      {
          Console.WriteLine("Test Started");
 
      }
 
      [TestCleanup]
      public  void testCleanUp()
      {
          Console.WriteLine("Test Ended");
 
      }


When you run all of your tests, you can see Test initialize and Test cleanup methods are called before and after each test method.

This is enough to get us started 😊





Comments

Popular posts from this blog

Specflow -Part3(Working with tables using Specflow.Assist.Dynamic)

Specflow -Part4(Specflow Scenario Outline and Feature Background )

C# Basics-Part 2(Namespaces,Properties,Constants and Read-Only Fields)