Pracuję nad aplikacją, która ma wiele warstw. Warstwa dostępu do danych do pobierania i zapisywania danych ze źródła danych, logika biznesowa do manipulacji danymi, interfejs użytkownika do wyświetlania danych na ekranie.
Robię również testy jednostkowe warstwy logiki biznesowej. Jedynym wymaganiem jest przetestowanie przepływu logiki warstwy biznesowej. Więc używam frameworku Moq, aby wyśmiewać warstwę dostępu do danych i testować jednostkę logiki biznesowej za pomocą MS Unit.
Korzystam z programowania interfejsów, aby rozdzielić projekt w jak największym stopniu, aby można było przeprowadzić test jednostkowy. Warstwa biznesowa warstwa dostępu do danych za pośrednictwem interfejsu.
Mam problem z próbą przetestowania jednej z metod logiki biznesowej. Ta metoda działa trochę, tworzy obiekt i przekazuje go do warstwy dostępu do danych. Kiedy próbuję kpić z tej metody warstwy dostępu do danych, nie może ona pomyślnie kpić.
Tutaj próbuję utworzyć kod demonstracyjny, aby pokazać mój problem.
Model:
public class Employee
{
public string Name { get; set; }
}
Warstwa dostępu do danych:
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);
}
}
Warstwa logiki biznesowej:
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 jednostkowy:
[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);
}
W przypadku testu jednostkowego w momencie drwiącym przesyłam obiekt pracownika, ale podczas wywoływania metody logiki biznesowej tworzy on inny obiekt pracownika wewnątrz metody. Dlatego nie mogę kpić z obiektu.
W takim razie jak zaprojektować, aby rozwiązać problem?
źródło
Odpowiedzi:
Zamiast tworzyć
Employee
obiekt bezpośrednio przy użyciunew
, twoja klasaBll
może użyćEmployeeFactory
do tego klasy, za pomocą metodycreateInstance
, która jest wstrzykiwana przez konstruktor:Konstruktor powinien poprowadzić obiekt fabryki przez interfejs
IEmployeeFactory
, aby można było łatwo zastąpić „prawdziwą” fabrykę sztuczną fabryką.Fabryka próbna może dostarczyć testowi dowolny
Employee
obiekt potrzebny do testu (na przykładcreateInstance
zawsze może zwrócić ten sam obiekt):Teraz użycie tej makiety w teście powinno załatwić sprawę.
źródło
Potraktowałbym to jako pojedynczą jednostkę do przetestowania.
Dopóki kontrolujesz wszystkie dane wejściowe, z których
Employee
obiekt jest tworzony, fakt, że jest on tworzony w testowanym obiekcie, nie powinien mieć znaczenia. Potrzebujesz tylko próbnej metody, aby zwrócić oczekiwany wynik, jeśli treść argumentu jest zgodna z oczekiwaniami.Oczywiście oznacza to, że musisz podać niestandardową logikę dla metody próbnej. Zaawansowanej logiki często nie można przetestować za pomocą jedynie próbnych „for x return y”.
W rzeczywistości, należy nie sprawiają, że powrót inny obiekt w testach niż to będzie w produkcji, bo jeśli nie, to nie byłoby testowanie kodu, który powinien go utworzyć. Ale ten kod jest integralną częścią kodu produkcyjnego i dlatego powinien być objęty również przypadkiem testowym.
źródło
Employee
obiekt do testów, nie przetestujesz kodu, który normalnie go tworzy. Więc nie powinieneś tego zmieniać.Niektóre narzędzia testujące zawodzą, zawsze musisz używać interfejsów, a wszystko musi być utworzone w sposób umożliwiający zamianę obiektu opartego na interfejsie na inny.
Istnieją jednak lepsze narzędzia - weź Microsoft Fakes (nazywało się Moles), które pozwalają zamienić dowolny obiekt, nawet statyczny i globalny. Zastępowanie obiektów wymaga bardziej niskiego poziomu, więc nie musisz wszędzie używać interfejsów, zachowując przy tym sposób pisania testów, do których jesteś przyzwyczajony.
źródło