Tuesday 31 July 2018

Unit Testing for Private Methods in DotNet C#

Though Microsoft doesn't allow creation of unit test of private method as best practice.  Microsoft Unit Testing recommends to Public methods with no parameters whereas class may contains private methods with lots of parameters. As we can see how Visual studio behave when we try to create unit test of private member.

Creation with non-public Class.





Creation with public Class.



See how it escape private Methods.






Solution:

PrivateObject Class Allows test code to call methods and properties on the code under test that would be inaccessible because they are not public.
References: 
https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.privateobject.aspx

Simple Demo:

IProgram.cs
using System;
namespace Private_Method_UnitTest
{
    public interface IProgram
    {
        string GetName();
    }
 
}


Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Private_Method_UnitTest
{
    public class Program : IProgram
    {
        public string GetName() => "Raj";
        private string GetAddress() => "Delhi";
        private string GetAddressWithParam(bool isPermanent) => (isPermanent? "Bihar":"Delhi");
    }
}

ProgramTests.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Private_Method_UnitTest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace Private_Method_UnitTest.Tests
{
    [TestClass()]
    public class ProgramTests
    {
 
        private IProgram program;
        [TestInitialize]
        public void Setup()
        {
            program = new Program();
        }
 
        [TestMethod()]
        public void GetNameTest()
        {
            var name = program.GetName(); 
            Assert.AreEqual(name, "Raj");
        }
 
 
        [TestMethod()]
        public void GetAddressTest()
        {
            Program objProgram = new Program();
            PrivateObject privateObject = new PrivateObject(objProgram);
            var result = privateObject.Invoke("GetAddress");
            var exceptadResult = "Delhi";
            Assert.AreEqual(result.GetType(), exceptadResult.GetType());
        }
 
        [TestMethod()]
        [ExpectedException(typeof(MissingMethodException))]
        public void GetAddress_Failour_Test()
        {
            Program objProgram = new Program();
            PrivateObject privateObject = new PrivateObject(objProgram);
            var result = privateObject.Invoke("GetAddress", 1);
        }
 
 
        [TestMethod()]
        public void GetAddressWithParam()
        {
            Program objProgram = new Program();
            PrivateObject privateObject = new PrivateObject(objProgram);
            var result = privateObject.Invoke("GetAddressWithParam"new object[] { true });
            var exceptadResult = "Bihar";
            Assert.AreEqual(result.GetType(), exceptadResult.GetType());
        }
 
    }
}