Ich arbeite an einer Anwendung, die mehrere Ebenen hat. Datenzugriffsschicht zum Abrufen und Speichern von Daten aus der Datenquelle, Geschäftslogik zum Bearbeiten von Daten, Benutzeroberfläche zum Anzeigen der Daten auf dem Bildschirm.
Ich mache auch Unit-Tests der Geschäftslogikschicht. Die einzige Anforderung besteht darin, den Ablauf der Business-Layer-Logik zu testen. Daher verwende ich das Moq-Framework, um die Datenzugriffsschicht zu verspotten und die Geschäftslogikschicht mit MS Unit zu testen.
Ich verwende die Schnittstellenprogrammierung, um das Design so weit wie möglich zu entkoppeln, damit ein Komponententest durchgeführt werden kann. Business-Schicht ruft Datenzugriffsschicht über Schnittstelle auf.
Ich habe ein Problem, wenn ich versuche, eine der Geschäftslogikmethoden zu testen. Diese Methode erledigt einige Arbeiten und erstellt ein Objekt und übergibt es an die Datenzugriffsschicht. Wenn ich versuche, diese Datenzugriffsschichtmethode zu verspotten, kann sie nicht erfolgreich verspottet werden.
Hier versuche ich, einen Demo-Code zu erstellen, um mein Problem zu zeigen.
Modell:
public class Employee
{
public string Name { get; set; }
}
Datenzugriffsschicht:
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);
}
}
Geschäftslogikschicht:
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;
}
}
Gerätetest:
[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);
}
Im Unit-Test-Fall zum Zeitpunkt des Verspottens sende ich ein Employee-Objekt, aber beim Aufrufen der Geschäftslogikmethode wird ein anderes Employee-Objekt innerhalb der Methode erstellt. Deshalb kann ich das Objekt nicht verspotten.
Wie soll ich in diesem Fall so gestalten, dass ich das Problem lösen kann?
quelle
Antworten:
Anstatt ein
Employee
Objekt direkt mit zu erstellennew
, könnte Ihre KlasseBll
hierfür eineEmployeeFactory
Klasse mit einer Methode verwendencreateInstance
, die über den Konstruktor eingefügt wird:Der Konstruktor sollte das Factory-Objekt über eine Schnittstelle führen
IEmployeeFactory
, damit Sie die "echte" Factory problemlos durch eine Mock-Factory ersetzen können.Die Scheinfabrik kann dem Test jede Art von
Employee
Objekt zur Verfügung stellen, die Sie für Ihren Test benötigen (z. B.createInstance
könnte immer dasselbe Objekt zurückgegeben werden):Jetzt sollte die Verwendung dieses Modells in Ihrem Test den Trick tun.
quelle
Ich würde es als eine Einheit zum Testen behandeln.
Solange Sie alle Eingaben steuern, aus denen das
Employee
Objekt erstellt wird, sollte die Tatsache, dass es im getesteten Objekt erstellt wird, keine Rolle spielen. Sie benötigen lediglich die Mock-Methode, um das erwartete Ergebnis zurückzugeben, wenn der Inhalt des Arguments der Erwartung entspricht.Dies bedeutet natürlich, dass Sie eine benutzerdefinierte Logik für die Mock-Methode bereitstellen müssen. Fortgeschrittene Logik kann oft nicht nur mit Mocks vom Typ "for x return y" getestet werden.
Tatsächlich sollten Sie dafür sorgen, dass es in den Tests kein anderes Objekt zurückgibt als in der Produktion, da Sie sonst den Code, der es erstellen soll, nicht testen würden. Dieser Code ist jedoch integraler Bestandteil des Produktionscodes und sollte daher auch vom Testfall abgedeckt werden.
quelle
Employee
in Tests ein anderes Objekt einfügen, testen Sie den Code, der es normalerweise erstellt, nicht. Sie sollten es also nicht ändern.Wenn einige Testtools fehlschlagen, müssen Sie immer Schnittstellen verwenden und alles muss so erstellt werden, dass Sie das schnittstellenbasierte Objekt gegen ein anderes austauschen können.
Es gibt jedoch bessere Tools - nehmen Sie Microsoft Fakes (wurde Moles genannt), mit denen Sie jedes Objekt austauschen können, auch statische und globale. Das Ersetzen von Objekten erfolgt auf niedrigerer Ebene, sodass Sie nicht überall Schnittstellen verwenden müssen, während Sie die gewohnten Schreibweisen für Tests beibehalten.
quelle