Assume you have the following method in your data access layer and you want to ensure it works as intended by writing an unit-test.
public class EmployeeRepository { public IList<IEmployee> GetEmployees() { string sql = "SELECT " + "FROM " + "ORDER BY ASC"; return Db.Read(sql); } }
It should be pretty clear that this method builds a SQL statement to fetch all employees from the database and calls the static ‘Read(string sql)’ method on the ‘Db’ class.
Ideally when I write the unit-test I would like to make sure the code under test is isolated from other methods, classes or tests. This means that for the method above I am only interested in the part which builds the SQL statement and the call to the ‘Read(string sql)’ method. However we are not interested in how the ‘Read(string sql)’ method executes. Normally you would create a mock of the ‘Db’ class and register an expectation on the ‘Read(string sql)’ method. Since we are dealing with a static class it is impossible to create a mock. Assuming we have access to the source code of the ‘Db’ class and there are no other libraries that link to the ‘Db’ class, we could go ahead and refactor the static class to an instance class but this will bring a few disadvantages:
- We need to refactor the ‘Db’ class to make it an instance class instead of static. This means we also need to apply the Singleton pattern to ensure the class only exists once in memory.
- All the code that uses the static class needs to be refactored to use the new Singleton class.
When we don’t have the source code of the ‘Db’ class (because it is part of a third party component) or there are other applications or libraries that rely on the static ‘Db’ class it is simply not possible to change the static class. So how do we test the method if we cannot change the ‘Db’ class. It took me a long time until I found the solution, which is actually pretty easy. Here is how I solved it:
public class EmployeeRepository { internal Func<string, IList<IEmployee>> ReadFromDb = (sql) => Db.Read(sql); public IList<IEmployee> GetEmployees() { string sql = "SELECT " + "FROM " + "ORDER BY ASC"; return ReadFromDb(sql); } }
I extracted the call to the ‘Read’ method of the ‘Db’ class by assigning it to the ‘Func
This allows me to replace the default initialization of the ‘ReadFromDb’ delegate in my unit-test with a different lambda expression which gives me access to the actual SQL statement. Such a unit-test could look like this:
[TestMethod] public void GetEmployeesTest() { string expectedSql = "SELECT " + "FROM " + "ORDER BY ASC"; string actualSql = string.Empty; EmployeeRepository target = new EmployeeRepository(); // Replace the ReadFromDb delegate by a custom lambda // expression to extract the SQL statement from the // GetEmployees method target.ReadFromDb = (sql) => { actualSql = sql; return new List<Employee>(); }; // Call the GetEmployees method to start the test target.GetEmployees(); // Check if the expectations are matched Assert.AreEqual(expectedSql, actualSql); }
One more thing that needs to be done is make the internals from the data access layer available for the test project. To do this add the following line in the ‘AssemblyInfo.cs’ of your data access layer project:
[assembly: InternalsVisibleTo("<assemblyname of test project>, PublicKey=<public key>")]
You can get the public key of an assembly using the ‘Sn’ command line tool like this:
Sn.exe -Tp <assemblyname>
Another nice way of getting the public key directly from within Visual Studio is described here: WebPart Tip: How to quickly view the public key for an assembly in the output window.