Testability of your Linq For Sql Model

I have already spoke with my friends about this. I think it’s the time to post it in my blog. Here is how I shield my implementation from the model.

Use an interface, not the class

Instead of using directly the DataModel generated by the Linq For Sql designer, you could use an interface representing your model.

public interface IDataContext
{
void SaveChanges();
}

public interface IEmployeeModel : IDataContext
{
void AddEmployee(Employee employee);
void DeleteEmployee(Employee employee);
IQueryable<Employee> Employees { get; }
}

We can see here that we have an interface that represent our model.

Customizing the generated partial class

The model generated by the Linq For Sql Designer is using a partial class. Using this feature, we can support for our IEmployeeModel interface. Here is how we do this:

partial class DataClasses1DataContext : IEmployeeModel
{
#region IEmployeeModel Members

public void AddEmployee(Employee employee)
{
if (employee == null)
throw new ArgumentNullException("employee");

this.Employees.InsertOnSubmit(employee);
}

void IEmployeeModel.DeleteEmployee(Employee employee)
{
if (employee == null)
throw new ArgumentNullException("employee");

this.Employees.DeleteOnSubmit(employee);
}

IQueryable<Employee> IEmployeeModel.Employees
{
get { return this.Employees; }
}

#endregion

#region
IDataContext Members

public void SaveChanges()
{
this.SubmitChanges();
}

#endregion
}

Implement a MockEmployeeModel class

After doing our real model, we can create a mock of our model to simulate database for very specific cases without touching the database. This way, we will be able to test even our Linq queries.



public class MockEmployeeModel : IEmployeeModel
{
private List<Employee> employees;

public MockEmployeeModel()
{
this.employees = new List<Employee>();
}

#region IEmployeeModel Members

public void AddEmployee(Employee employee)
{
if (employee == null)
throw new ArgumentNullException("employee");

this.employees.Add(employee);
}

public void DeleteEmployee(Employee employee)
{
if (employee == null)
throw new ArgumentNullException("employee");

this.employees.Remove(employee);
}

public IQueryable<Employee> Employees
{
get { return this.employees.AsQueryable(); }
}

#endregion

#region
IDataContext Members

public void SaveChanges()
{
// Nothing special to do here.
}

#endregion
}

Limitations


  • Compiled Linq queries are not supported. I will probably show you in a next post how to support it.


  • The MockModel is very limited. We would probably benefit having a mocking framework here.

Conclusion

As a typical use, we can now use normal linq queries over our model and test our queries in the very same manner using our MockEmployeeModel. This approach works with ADO.Net Entity Framework as well.



Happy Programming!

0 comments: