Go Back
  • Some TDD in the real world

    One of the most common things that I run into when doing TDD with NUnit in the 'real world' is that the ugly truth is dependencies are either hard or impossible to test.

     

    Take for example this code snippet where we're calling a webservice a couple times to do some work.

        public class HumanResources

     

        {

            public void FireThisGuy(long employeeId)

            {

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                Employee emp = service.GetEmployee(request).Employee;

                emp.TerminationDate = DateTime.Now;

     

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

        }

     

     

     

     

     

    We know it's a bad practice to call webservices in our unit tests for a few reasons. (namely it's slow). So let's refactor a little and remove anything related to the webservices out. I extract method on the get...

           public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

     

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

     

    notice this wasn't a straight up 'extract to method' on your refactoring tool. I did about 5 small refactorings before i did the extract but just notice the complete extraction of the dependency on the webservice to a new method "GetEmployeeById".

     

    now the same for the set:

     

           public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

                SetEmployee(emp);

            }

     

            protected void SetEmployee(Employee emp)

            {

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

     

    now for my unit test the only thing i really want to test is the "FireThisGuy" logic. so first i would need to inherit from HumanResources and make a testing class that overrides the 2 dependencies i do not want.

        public class HumanResources

        {

            public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

                SetEmployee(emp);

            }

     

            protected virtual void SetEmployee(Employee emp)

            {

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected virtual Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

        }

        public class TestingHumanResources : HumanResources

        {

            public Employee GetEmployeeByIdTestingEmployee { get; set; }

            protected override Employee GetEmployeeById(long employeeId)

            {

                return GetEmployeeByIdTestingEmployee;

            }

     

            public Employee SetTestingEmployee { get; set; }

            protected override void SetEmployee(Employee emp)

            {

                SetTestingEmployee = emp;

            }

        }

     

     

     

     

     

     

     

     

     

    Now i can actually write a test that validates

      public class HumanResources

        {

            public void FireThisGuy(long employeeId)

            {

                Employee emp = GetEmployeeById(employeeId);

                emp.TerminationDate = DateTime.Now;

                SetEmployee(emp);

            }

     

            protected virtual void SetEmployee(Employee emp)

            {

                HumanResourcesService service = new HumanResourcesService();

                SetEmployeeRequest setRequest = new SetEmployeeRequest();

                setRequest.Employee = emp;

                service.SetEmployee(setRequest);

            }

     

            protected virtual Employee GetEmployeeById(long employeeId)

            {

                Employee emp;

                HumanResourcesService service = new HumanResourcesService();

                GetEmployeeRequest request = new GetEmployeeRequest();

                request.EmployeeId=employeeId;

                emp = service.GetEmployee(request).Employee;

                return emp;

            }

        }

        public class TestingHumanResources : HumanResources

        {

            public Employee GetEmployeeByIdTestingEmployee { get; set; }

            protected override Employee GetEmployeeById(long employeeId)

            {

                return GetEmployeeByIdTestingEmployee;

            }

     

            public Employee SetTestingEmployee { get; set; }

            protected override void SetEmployee(Employee emp)

            {

                SetTestingEmployee = emp;

            }

        }

        [TestFixture]

        public class HumanResourcesTests

        {

            [Test]

            public void FireThisGuy_UserIdIn_FiredEmployeeSaved()

            {

                TestingHumanResources hr = new TestingHumanResources();

                hr.GetEmployeeByIdTestingEmployee = new Employee();

                hr.GetEmployeeByIdTestingEmployee.TerminationDate = null;

     

                hr.FireThisGuy(200);

                Assert.IsNotNull(hr.SetTestingEmployee.TerminationDate);

     

            }

        }

     

     

     

     

     

     

     

     

     

     

     

     

     

    This is why im a big fan of object oriented programming and using inheritance to break dependencies. It's a real fast solution to some of the unique dependency issues i fight every day and it is a lot easier to read and debug than tons of interfaces.  This and other examples of seaming and seperation can be found in Michael Feather's book "Working Effectively with Legacy Code"

     

     

     

     

    Grab the code here

    Full story

    Comments (10)