Wednesday, October 30, 2013

Test Driven Development - Part V - Dealing External Dependency with Mock

As I mentioned in the previous session, Stubs are used to test the logic of the class under test  without considering how the dependant objects interact with thc class under test. Some times we need to test how the class under test interacts with the dependant objects or we need to make sure that the class under test interacts correctly with the dependant objects. Mocks are being used in this scenario. So by using Mocks, we are testing wheather the class under test has interacted correctly with the dependant object by verifying the Mock object.


Consider a scenario like the FileUpload class is logging the errors  and whenever an exception happens to the logging, it will mail the exception to the given mail address. Here we are using two dependent classes. One is for logging the errors and one for mailing the exception. If you want to test whether the mails are sending correctly for the exceptions we have to check the mail service object. For that we have to use the  Mock. A stub can be applied for Log service object. The below code shows how to implement it.

1. LogService Interface

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace ManualMock_TDD  
 {  
   public interface ILogService  
   {  
     void WriteLog(string logmessage);  
   }  
 }  

2. MailService Interface

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace ManualMock_TDD  
 {  
   public interface IEmailService  
   {  
     void SendEmail(string To, string Subject, string Body);  
   }  
 }  

3. The FileUpload Class

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.IO;  
 using ManualMock_TDD;  
 namespace Simple_TDD  
 {  
   public class FileUpload  
   {  
     private ILogService _LogService;  
     private IEmailService _Email;  
     public ILogService LogService  
     {  
       get { return _LogService; }  
       set { _LogService = value; }  
     }  
     public IEmailService EmailService {  
       get {return _Email ;}  
       set {_Email=value ;}  
     }  
     public void ValidateFilename(string filename)   
     {  
       //return ValidateObj.IsValid(filename);  
       if (filename.Length < 8)  
       {  
         try  
         {  
           LogService.WriteLog("file name is too short");  
         }  
         catch (Exception ex)  
         {  
           EmailService.SendEmail("mail@me.com", "Error occured while writing log", ex.Message);   
         }  
       }  
     }  
   }  
 }  

4. The Unit Test Class

 using Simple_TDD;  
 using Microsoft.VisualStudio.TestTools.UnitTesting;  
 using System;  
 namespace ManualMock_TDD.Tests  
 {  
   [TestClass()]  
   public class FileUploadTest  
   {  
     [TestMethod]  
     public void ValidateFilename_EmptyFileName_WillSendEmail()  
     {  
       StubLogService logservice = new StubLogService();  
       logservice.ToThrow = new Exception("filename to short");  
       MockEmailService eMailService = new MockEmailService();  
       FileUpload Target = new FileUpload();  
       Target.LogService = logservice;  
       Target.EmailService = eMailService;  
       Target.ValidateFilename("abc.txt");  
       Assert.AreEqual("mail@me.com", eMailService.To);  
       Assert.AreEqual("Error occured while writing log", eMailService.Subject);  
       Assert.AreEqual("filename too short", eMailService.Body);  
     }  
   }  
   class StubLogService : ILogService  
   {  
     public Exception ToThrow;  
     public void WriteLog(string msg)  
     {  
       throw ToThrow;  
     }  
   }  
   class MockEmailService : IEmailService  
   {  
     public string To;  
     public string Subject;  
     public string Body;  
     public void SendEmail(string to,string subject,string body)  
     {  
       To = to;  
       Subject = subject;  
       Body = body;  
     }  
   }  
 }  


In the example, the FileUpload class is using two interface objects. One for log service and another for email service.  For unit testing we use stub for  Log Service and mock object for Email. We need mock object for email here because we are going to check the content of the mail sent by the FileUpload class. To generate the scenario, the StubLogService will throw an exception. Then the FileUpload class will  call the mail service and will send the exception to the address given. The assertions will be done on the mail object. The last three lines in the test method is verifying the mail object to ensure about the exception handled in the  FileUpload class

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.