vendredi 8 juillet 2011

Comment mocker un DataContext et une Table LINQ to SQL avec Moles

Avez-vous déjà essayés de mocker un DataContext ou une table LINQ to SQL? Cette tâche est ardue à réaliser avec des plateformes de mocking classiques, car le DataContext n’hérite d’aucune interface et la classe Table est sealed. Heureusement, Moles apporte une solution toute simple. Moles est un framework qui permet de détourner n’importe quelle méthode .NET, incluant même les méthodes virtuelles/statiques dans des classes sealed.

Allons-y d’un exemple! Nous avons ici une application WinForms classique contenant un fichier DataClassesEmployee.dbml. Ce fichier contient une table Employee. C’est cette table que l’on va mocker.



Nous avons également une opération EmployeeGetOperation qui se charge de trouver un employé dans la base de données en fonction de son Id.


public class EmployeeGetOperation
{
private Int32 _id = -1;
public Int32 Id
{
get { return _id; }
set { _id = value; }
}

private Employee _result = null;
public Employee Result
{
get { return _result; }
set { _result = value; }
}

DataClassesEmployeeDataContext _context = new DataClassesEmployeeDataContext();
public DataClassesEmployeeDataContext Context
{
get { return _context; }
set { _context = value; }
}

public EmployeeGetOperation(Int32 Id)
{
this.Id = Id;
}

public EmployeeGetOperation(Int32 Id, DataClassesEmployeeDataContext Context)
: this(Id)
{
this.Context = Context;
}

public void Execute()
{
Result = Context.Employees.FirstOrDefault(e => e.ID == Id);
}
}


Nous allons maintenant ajouter un projet de test à notre solution afin de pouvoir créer notre test unitaire. N'oubliez pas d'ajouter la référence System.Data.Linq et celle du projet qui contient votre fichier dbml (MockingLINQtoSQLApp) à votre projet de test. La prochaine étape est de générer un fichier moles pour les 2 références ci-dessus. Pour ce faire vous cliquer droit sur la référence dans votre projet de test et ensuite cliquer sur "Add Moles Assembly". Répéter l'opération pour System.Data.Linq.



Nous voilà rendus au test unitaire. La première étape sera d'instancier un MDataClassesEmployeeDataContext via les nouveaux types générés par Moles, ensuite nous créerons une table d'employé à partir d'une liste fictive et finalement nous détournerons notre propriété Employees de notre nouveau DataContext vers notre table fictive.

Voici maintenant le code de notre test unitaire EmployeeGetOperationTests.


[TestClass]
public class EmployeeGetOperationTests
{
[TestMethod]
[HostType("Moles")]
public void EmployeeGetOperationTests_GetValidUser_ReturnValidUser()
{
//Mock du DataContext
var context = new MDataClassesEmployeeDataContext();

//Liste d'employé fictive à utiliser pour le test
var employees = new List<Employee>()
{
new Employee() { ID = 1, FirstName = "Bud", LastName = "Spencer"},
new Employee() { ID = 2, FirstName = "Terence", LastName = "Hill"}
};

//Créer une table à partir de notre liste fictive
MTable<Employee> employeeMockTable = SetupLinqTable(employees);

//Détourner la propriété Employees de notre context vers notre table fictive
context.EmployeesGet = () => employeeMockTable;

//Appeler notre opération de sélection d'un employé via notre context mocké
EmployeeGetOperation operation = new EmployeeGetOperation(1, context);
operation.Execute();
//Vérifier que l'employé retourné est bien celui que nous attendions
Assert.AreEqual<Int32>(1, operation.Result.ID);
Assert.AreEqual<String>("Bud", operation.Result.FirstName);
Assert.AreEqual<String>("Spencer", operation.Result.LastName);
}

//Fonction qui retourne une Table à partir d'un IEnumerable
private MTable<T> SetupLinqTable<T>(IEnumerable<T> linqList) where T : class
{
MTable<T> tempTable = new MTable<T>();
tempTable.Bind(linqList.AsQueryable());
return tempTable;
}
}


Il est maintenant temps de rouler le test.



Voilà! Nous avons créé un test unitaire en mockant la couche d'accès aux données (LINQ to SQL) grâce à Moles!

Aucun commentaire:

Enregistrer un commentaire