Je travaille sur une application à plusieurs couches. Couche d'accès aux données pour récupérer et enregistrer les données de la source de données, logique métier pour manipuler les données, interface utilisateur pour afficher les données à l'écran.
Je fais également des tests unitaires de la couche logique métier. La seule exigence est de tester le flux de la logique de la couche métier. J'utilise donc le framework Moq pour simuler la couche d'accès aux données et tester unitairement la couche de logique métier avec MS Unit.
J'utilise la programmation d'interface pour faire le plus possible découpler la conception afin que le test unitaire puisse être effectué. La couche métier appelle la couche d'accès aux données via l'interface.
Je rencontre un problème lorsque j'essaie de tester l'une des méthodes de logique métier. Cette méthode fonctionne et crée un objet et le transmet à la couche d'accès aux données. Lorsque j'essaie de se moquer de cette méthode de couche d'accès aux données, elle ne peut pas se moquer avec succès.
Ici, j'essaie de créer un code de démonstration pour montrer mon problème.
Modèle:
public class Employee
{
public string Name { get; set; }
}
Couche d'accès aux données:
public interface IDal
{
string GetMessage(Employee emp);
}
public class Dal : IDal
{
public string GetMessage(Employee emp)
{
// Doing some data source access work...
return string.Format("Hello {0}", emp.Name);
}
}
Couche logique métier:
public interface IBll
{
string GetMessage();
}
public class Bll : IBll
{
private readonly IDal _dal;
public Bll(IDal dal)
{
_dal = dal;
}
public string GetMessage()
{
// Object creating inside business logic method.
Employee emp = new Employee();
string msg = _dal.GetMessage(emp);
return msg;
}
}
Test de l'unité:
[TestMethod]
public void Is_GetMessage_Return_Proper_Result()
{
// Arrange.
Employee emp = new Employee; // New object.
Mock<IDal> mockDal = new Mock<IDal>();
mockDal.Setup(d => d.GetMessage(emp)).Returns("Hello " + emp.Name);
IBll bll = new Bll(mockDal.Object);
// Act.
// This will create another employee object inside the
// business logic method, which is different from the
// object which I have sent at the time of mocking.
string msg = bll.GetMessage();
// Assert.
Assert.AreEqual("Hello arnab", msg);
}
Dans le cas de test unitaire au moment de la moquerie, j'envoie un objet Employee, mais lorsque j'appelle la méthode de logique métier, cela crée un objet Employee différent à l'intérieur de la méthode. C'est pourquoi je ne peux pas me moquer de l'objet.
Dans ce cas, comment concevoir pour que je puisse résoudre le problème?
la source
Réponses:
Au lieu de créer un
Employee
objet directement en utilisantnew
, votre classeBll
pourrait utiliser uneEmployeeFactory
classe pour cela, avec une méthodecreateInstance
, qui est injectée via le constructeur:Le constructeur doit prendre l'objet d'usine à travers une interface
IEmployeeFactory
, de sorte que vous pouvez facilement remplacer la «vraie» usine par une usine factice.L'usine de simulation peut fournir au test tout type d'
Employee
objet dont vous avez besoin pour votre test (par exemple,createInstance
pourrait toujours retourner le même objet):Maintenant, utiliser cette maquette dans votre test devrait faire l'affaire.
la source
Je le traiterais comme une seule unité à tester.
Tant que vous contrôlez toutes les entrées à partir desquelles l'
Employee
objet est créé, le fait qu'il soit créé dans l'objet testé n'a pas d'importance. Vous avez juste besoin d'une méthode the mock pour retourner le résultat attendu si le contenu de l'argument correspond à l'attente.Évidemment, cela signifie que vous devez fournir une logique personnalisée pour la méthode fictive. La logique avancée ne peut souvent pas être testée avec des types de moquerie «pour x retour y».
En fait, vous ne devriez pas lui faire retourner un objet différent dans les tests que dans la production, car si vous le faisiez, vous ne testeriez pas le code qui devrait le créer. Mais ce code fait partie intégrante du code de production et devrait donc également être couvert par le cas de test.
la source
Employee
objet différent dans les tests, vous ne testerez pas le code qui le crée normalement. Vous ne devriez donc pas le changer.C'est un échec de certains outils de test, vous devez toujours utiliser des interfaces et tout doit être créé de manière à vous permettre d'échanger l'objet basé sur l'interface pour un autre.
Cependant, il existe de meilleurs outils - prenez Microsoft Fakes (était appelé Moles) qui vous permet d'échanger n'importe quel objet, même statique et global. Il faut une approche de plus bas niveau pour remplacer les objets afin que vous n'ayez pas à utiliser les interfaces partout tout en conservant la façon d'écrire les tests auxquels vous êtes habitué.
la source