Stubs and Shims
Stubs and Shims
Stubs: Stubs replace the functionality with the different implementation. One should have interface based programming i.e. we cannot directly instantiate a class, instead you should be using the interface (which helps in replacing the original functionality with the stub, based on the same interface).
Shims: Replace the functionality provided by .NET framework. It modifies the complied code at runtime to replace the method call.
Stubs Example: The functionality in class EmployeeRepositrywill search for an employee in the list. This class implement the interface IEmployeeRepositry
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public interface IEmployeeRepositry
{
Employee FindEmployee(Employee emp);
}
public class EmployeeRepositry : IEmployeeRepositry
{
List<Employee> list;
public EmployeeRepositry()
{
list = new List<Employee>{new Employee{FirstName = "Girish",LastName = "Goudar" },
new Employee{FirstName = "Deepak",LastName = "H" }};
}
public Employee FindEmployee(Employee emp)
{
return list.Find(item =>item.FirstName.Equals(emp.FirstName));
}
}
**Unit testing without stubs:**Unit test calls the Employee repository FindEmployeemethod to search for an employee
** **
** ** publicvoid TestMethod1()
{
Employeeemp = newEmployee();
emp.FirstName = "Girish";
emp.LastName = "Singh";
IEmployeeRepositryrepositry = newEmployeeRepositry();
Employeeemployee = repositry.FindEmployee(emp);
Assert.AreEqual(emp.FirstName,employee.FirstName);
}
}
Unit testing with stubs: Generate the fakes assembly using the Microsoft fakes framework and the stub methods will be generated as shown.
** **
** **
The stub method is created as “FindEmployeeEmployee”.The name convention used will be first the name of the method and then the type of parameter name
** **
The Interface IEmployeeRepositry this time will use the stub employee repository and provide its own implementation of the FindEmployee method.
** **
** **
** ** publicvoid TestMethod1()
{
Employee emp = new Employee();
emp.FirstName = "Girish";
emp.LastName = "Singh";
** IEmployeeRepositry repositry = new StubIEmployeeRepositry()**
** {**
** FindEmployeeEmployee = emp1 =>**
** {**
** return new Employee { FirstName ="Mohan",LastName ="v"};**
** }**
** };**
Employee employee = repositry.FindEmployee(emp);
Assert.AreEqual(emp.FirstName,employee.FirstName);
}
**Shims Example:**The functionality in class EmployeeRepositrywill search for an employee in the list.Shims can be used to replace calls to assemblies that you cannot modify, such .NET assemblies.
public class EmployeeRepositry
{
List<Employee> list;
public EmployeeRepositry()
{
list = newList<Employee>{newEmployee{FirstName = "Girish",LastName = "Goudar" },
newEmployee{FirstName = "Deepak",LastName = "H" }};
}
public Employee FindEmployee(Employee emp)
{
returnlist.Find(item =>item.FirstName.Equals(emp.FirstName));
}
**Unit testing with shims:**Consider the EmployeeRepositryClass to be part of3rd party solution or legacy code which cannot be refactored by us. Use the shims created by Microsoft fakes framework as shown.
publicvoid TestMethod1()
{
Employee emp = new Employee();
emp.FirstName = "Girish";
emp.LastName = "Singh";
using (ShimsContext.Create())
{
EmployeeRepositryrepositry = new ShimEmployeeRepositry()
{
FindEmployeeEmployee = emp1 =>
{
return new Employee { FirstName = "Girish", LastName = "v" };
}
};
Employee employee = repositry.FindEmployee(emp);
Assert.AreEqual(emp.FirstName, employee.FirstName);
}
}
Difference between stubs and shims
** **
|
Stubs |
Shims |
Static methods, sealed types |
You can only use stubs to implement interfaces. Therefore, stub types cannot be used for static methods, non-virtual methods, sealed virtual methods, methods in sealed types |
Shims can be used for Static methods and sealed types |
Internal types |
Stubs can be used with internal types that are made accessible by using the assembly attribute InternalsVisibleToAttribute. |
Shims can be used with internal types that are made accessible by using the assembly attribute InternalsVisibleToAttribute. |
Private methods |
Stubs can only replace visible methods. |
Shims can replace calls to private methods if all the types on the method signature are visible. |
Interfaces and abstract methods |
Stubs provide implementations of interfaces and abstract methods that can be used in testing |
Shims can’t instrument interfaces and abstract methods, because they don’t have method bodies. |
Performance |
Stubs do not have this performance overhead and are as fast as virtual methods can go |
Shims run slower because they rewrite your code at run time |