Come abbiamo già sottolineato una delle caratteristiche di Asp.Net MVC è la propensione del framework alla testabilità dei controller realizzati, opportunamente isolati, in modo da rendere la manutenibilità delle nostre applicazioni un obiettivo facilmente raggiungibile.
Testare un controller significa sottoporre a unit testing le varie action che lo compongono, verificando che il risultato dell'elaborazione sia quello aspettato. Potremmo quindi testare il nostro controller ChiSiamoController esaminato precedentemente, ma per il suo isolamento abbiamo bisogno di un oggetto Fake che sostituisca l'implementazione reale del servizio che restituisce i testi delle pagine:
public class FakeTestiServices : ITestiWebServices
{
public GEMCore.DTO.Web.TestoDTO RecuperaTesto(string id)
{
return new GEMCore.DTO.Web.TestoDTO()
{
Id = id,
Titolo = "Chi Siamo",
Testo = "Pagina Chi Siamo"
};
}
}
Isolato il controller possiamo verificare che il DTO restituito sia di tipo TestoDTO
e coincida con quello fake:
[TestClass]
public class ChiSiamoControllerTest
{
[TestMethod]
public void IndexTest()
{
FakeTestiServices services = new FakeTestiServices();
ChiSiamoController controller = new ChiSiamoController(services);
ViewResult view = (ViewResult)controller.Index();
var model = view.ViewData.Model;
Assert.IsInstanceOfType(model, typeof(TestoDTO));
Assert.AreEqual("Chi Siamo", ((TestoDTO)model).Titolo);
Assert.AreEqual("Pagina Chi Siamo", ((TestoDTO)model).Testo);
}
}
Sfruttando l'implementazione che fa uso di unity ci basta cambiare la dipendenza iniettata nel nostro progetto di testing ed esporre pubblicamente un metodo della factory per recuperare il controller di cui abbiamo bisogno.
[TestClass]
public class ChiSiamoControllerTest
{
[TestMethod]
public void IndexTest()
{
UnityControllerFactory factory = new UnityControllerFactory();
ChiSiamoController controller =
(ChiSiamoController) factory.GetController(typeof(ChiSiamoController));
ViewResult view = (ViewResult)controller.Index();
var model = view.ViewData.Model;
Assert.IsInstanceOfType(model, typeof(TestoDTO));
Assert.AreEqual("Chi Siamo", ((TestoDTO)model).Titolo);
Assert.AreEqual("Pagina Chi Siamo", ((TestoDTO)model).Testo);
}
}
Mocking
Chiaramente buona parte del lavoro noioso di questa attività è realizzare questi oggetti Fake per l'isolamento del controller, cosa che possiamo demandare a framework appositi, detti di Mocking, istruendoli opportunamente su come generare per noi le classi.
Useremo RhinoMocks, ma i concetti sono gli stessi anche per gli altri framework. Il nostro test diventa il seguente:
[TestClass]
public class ChiSiamoControllerTest
{
[TestMethod]
public void IndexTest()
{
MockRepository mocks = new MockRepository();
ITestiWebServices services = mocks.StrictMock();
Expect.Call(services.RecuperaTesto("chisiamo")).Return(new TestoDTO()
{
Titolo = "Chi Siamo",
Testo = "Pagina Chi Siamo"
});
mocks.ReplayAll();
ChiSiamoController controller = new ChiSiamoController(services);
ViewResult view = (ViewResult)controller.Index();
var model = view.ViewData.Model;
Assert.IsInstanceOfType(model, typeof(TestoDTO));
Assert.AreEqual("Chi Siamo", ((TestoDTO)model).Titolo);
Assert.AreEqual("Pagina Chi Siamo", ((TestoDTO)model).Testo);
}
}
RhinoMocks crea per noi un'implementazione dell'interfaccia a runtime che si comporta come specificato attraverso la configurazione fatta in questo caso usando la fluent interface: quando viene invocato il metodo RecuperaTesto con id "chisiamo" restituisci un'istanza di TestoDTO
con Titolo
e Testo
specificati.