Destul de tirziu mi-am dat seama de beneficiile aduse de un Mock – dar mai bine mai tirziu decit niciodata …
Ma gindeam ca niciodata nu o sa il folosesc – ca ajunge sa verific BLL cu unit test(NUNIT/VS Test) , site-ul Web cu NUnit ASP/WATI(N|R) / Selenium , Windows Forms cu NUnitForms si nu o sa am nevoie de Mock.
Adevarul este ca da, nu as avea nevoie de Mock … decit daca as vrea sa verific mai repede unele date, fara sa ating BD.De exemplu, pot sa verific controller-ele fara sa am nevoie sa instantiez HttpContext si BD. Sa zicem ca am un controller care are o actiune ce doar exporta un fisier Word– bazat pe un template. Codul din fisier arata cam asa :
public ActionResult ExportDate(string id)
{
IDateExport fe = ObjectFactory.GetInstance<IDateExport>();
fe.id = id;
export exp = new export(Server.MapPath("~/bin/Templates"));
FileContentResult fcr = new FileContentResult(exp.Export(fe), "application/ms-word");
fcr.FileDownloadName = fe.Number + ".doc";
return fcr;
}
Daca as vrea sa verific rapid metoda aceasta ar trebui sa nu ating baza de date si sa am pun un rezultat in loc de Server.MapPath ?
Se vede clar ca deja folosesc StructureMap, deci nu ar fi o problema cu gasitul a niste date fake. Dar pentru Server.MapPath intervine stralucit Mock.
Am preluat de la Hanselmann MVC Mock Helpers ,iar codul de test arata cam asa :
exportController i = new exportController();
MockRepository mocks = new MockRepository();
using (mocks.Record())
{
//MvcMockHelpers.SetFakeControllerContext(mocks, i);
mocks.SetFakeControllerContext(i);
SetupResult.For(i.ControllerContext.HttpContext.Server.MapPath(null)).IgnoreArguments().Return(@"c:\programs\templates"); // cod pentru chemarea Server.MapPath
mocks.ReplayAll();
}
using (mocks.Playback())
{
ObjectFactory.Initialize(x =>
{
x.ForRequestedType<IExport>().TheDefaultIsConcreteType<FactFind>();// FactFind nu atinge BD
});
FileContentResult fcr = i.exportdate("865", "A") as FileContentResult;
fcr.ShouldNotBeNull();
fcr.FileContents.Length.ShouldBeGreaterThan(0);//TODO : Verifica si continutul
}
Pai teoria cel putin, in ce priveste unit testing, zice ca nu e vorba de "a se executa mai rapid", sau daca atinge db sau nu, ci de faptul ca fiecare unit test ar trebuie sa testeze strict codul dintr-o o metoda anume, fara sa ajung sa testeze nici o alta metoda din cele apelate (direct sau indirect) de acea metoda..
E clar ca asta implica un efort in plus, trebuie gandit codul a.i. dependintele codului testat sa fie cat mai putine, si in loc de toate dependintele ramase trebuie folosite clase "fake", fie scrise manual, fie generate automat cu un framework de mocking..