Monday, October 28, 2013

Test Driven Development - Part IV - Dealing with External Dependency using Stub

An external dependency is an object in your system that your code under test interacts with, and over which you have no control. (Common examples are filesystems, threads, memory, time, and so on.). Mocks and Stubs are used to deal with external dependency. Both are fake objects to represent external dependent objects.Before going deep into mock and stub, we have to know how to refactor our code to apply mocks and stubs. Refactoring is the act of changing the code’s design without breaking existing functionality.

Consider our file upload class we used in the previous session. Assume that we have a file stored in the filesystem which consist of the rules related to the validation. The file upload class will have to validate the file name against the rules in the file. In this case, there we have a Validate class which deals with the accessing the file and validating the file name.   This Validate class is the dependency class of File upload class.
In order to break the dependency, we have to add one more layer of indirection. It can be either an Abstract Class or an Interface. Both have its own advantages and disadvantages. Here I am using Interface as the layer of indirection. So we have to do the following
  1. Extract an interface to allow replacing underlying implementation.
  2. Receive an interface at the constructor level or as a property.
After refactoring our code to a loosely coupled architeture, we can easily inject mock or stub into the application for the purpose of testing

STUB


Stub is a fake object the class under test has depended on. Stubs are used to by pass an external dependency. If a class is having external dependency, the unit test will fail when the dependency fails even if the logic in the Class Under Test is correct. Stubs are used to overcome this kind of issues. The unit test will test the class under test and during the process the Class Under Test will call the Stub class  instead of  calling the real external dependent object which will return the expected result to the class under test. The assertion is done with the class under test.

Example

IValidate Interface
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace ManualStub_TDD  
 {  
   public interface IValidate  
   {  
     bool IsValid(string Filname);  
   }  
 }  

FileUpload class

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.IO;  
 using ManualStub_TDD;  
 namespace Simple_TDD  
 {  
   public class FileUpload  
   {  
     private IValidate ValidateObj;  
     public IValidate ValidationObj {   
       get{return ValidateObj;}  
       set { ValidateObj = value; }  
     }  
     public bool ValidateFilename(string filename)   
     {  
       return ValidateObj.IsValid(filename);  
     }  
   }  
 }  

Unit Testing project
 using Simple_TDD;  
 using Microsoft.VisualStudio.TestTools.UnitTesting;  
 using System;  
 using ManualStub_TDD;  
 namespace ManualStub.Tests  
 {  
   [TestClass()]  
   public class FileUploadTest  
   {  
     [TestMethod]  
     public void ValidateFileName_FilenameShorterThan6Letters_ReturnsFalse()  
     {  
       ValidateStub Vstub = new ValidateStub();  
       Vstub.StubReturnValue = false;  
       FileUpload target = new FileUpload();  
       target.ValidationObj = Vstub;  
       bool actual = target.ValidateFilename("abc.txt");  
       Assert.AreEqual(false, actual, "Method Allows shorter filenames");  
     }  
   }  
 }  
  class ValidateStub : IValidate  
 {  
   public bool StubReturnValue;  
   public bool IsValid(string filename)  
   {  
     return StubReturnValue;  
   }  
 }  


Here there is an IValidate interface and it contain the IsValid method. The Validate class will implement the IValidate interface. The "ValidationObj" prpoerty in the FileUpload class  will hold instance of classes implementing Ivalidate interface.  The ValidateFilename method will use this property to validate the file name and will return the boolean result.

For the purpose of unit testing, an internal stub class is created which implements the Ivalidate interface. To control the output, one more property has been added to the class. The stub will be initialized  in the Test Method. And that stub will be passed to the Target as property. And the method will evaluate the class under test.

No comments:

Post a Comment