2009-09-17 5 views
6

Ich habe meine mvc-Basis-Controller namens DefaultController mit Dependency-Injection-Muster implementiert, um Testfälle zu konstruieren. Beispiel unten:Wie löst man die Abhängigkeit der Base Controller-Abhängigkeit zu Testzwecken?

public class DefaultController : Controller 
{ 
    protected readonly ISessionHelper _sessionHelper; 
    string _thisUserOpenID; 
    protected IUsersRepository _UserRepository; 
... 
    public DefaultController() 
    { } //not for testing 

    public DefaultController(ISessionHelper session, IUserRepository repo) 
    { 
     _sessionHelper=session; 
     _UserRepository = repo; 
    } 
} 

Dann habe ich meinen Controller mit diesem Controller, Homecontroller, Usercontroller etc.

nun einige Testfälle Aufbau ich mich in einer Situation gefunden, wo ich nicht weiß, wie man tatsächlich Verwenden Sie das Injektionsabhängigkeitsmuster.

[TestMethod] 
    public void Welcome_Message_In_ViewData_Has_Coockie_User_Display_Name() 
    { 
     // Below I want to insert FakeRepositories using 
     //ISessionHelper and so on. but the constructor 
     //for homecontroller don't have it. 
     HomeController controller = new HomeController(); 

Irgendwelche Ideen?

Antwort

5

Ihr HomeController muss einen passenden "injizierbaren" Konstruktor haben, der dann den Basiskonstruktor aufrufen würde.

public HomeController(ISessionHelper session, IUserRepository repo) 
    : base(session, repo) 
    { 

    } 

nun in Ihrem Test, würden Sie Ihren Homecontroller mit diesem Konstruktor erstellen und in einer verspottet Sitzung und Benutzer-Repository übergeben. Apropos Spott, Sie könnten auch interessiert sein an Scott Hanselman's MvcMockHelpers classes, mit Code für viele beliebte Mock Frameworks.

3

Ich sehe nicht, warum Sie zwei Konstruktoren haben. Sie sollten nur einen haben, den Konstruktor ohne Parameter loswerden. Mit einem DI-Framework wie Castle Windsor, oder meinem bevorzugten, wird Autofac all dies für Sie erledigen. Dann, was das Testen betrifft, verwende so etwas wie Moq. Ie

public DefaultController(ISessionHelper session, IUserRepository repo) 
{ 
    _sessionHelper = session; 
    _UserRepository = repo; 
} 

Registrieren Sie DefaultController, ISessionHelper und IUserRepository mit Ihrem DI-Framework. Etwas entlang der Linien von:

Register(new DefaultController()); (it is something like that in Autofac) 
Register<SessionHelper>().As<ISessionHelper>(); 
Register<UserRepository>().As<IUserRepository>(); 

Auf diese Weise können Sie default aus dem Behälter ziehen und der DI-Rahmen wird die beiden Parameter für Sie injizieren. Ich wickle eine statische Methode bis zu meinem DI-Container zugreifen, es sieht aus wie:

var controller = IoC.Resolve<DefaultController>(); 

Grundsätzlich über Autofac Kopf und einen Blick haben. Es gibt auch ein Web-Modul zum Registrieren Ihrer Controller für Sie.

Dann zum Testen verwenden Sie einfach Moq, oder finden Sie eine Form von "AutoMocker" (google it). Ich würde tun:

var session = new Mock<ISessionHelper>(); 
var repo = new Mock<IUserRepository>(); 
repo.Setup(s => s.FindById(123)).Returns(new User()); 

var conroller = new DefaultController(session.Object, repo.Object); 
controller.Execute(); 

Auch ewww Repositories. Mit .Net und Generika etc ... erstellen Sie sich einfach eine nette ISession.

var session = IoC.Resolve<ISession>(); 
var user1 = session.Get<User>(123); 
var user2 = session.Get<User>(u => u.Username == "admin"); 
session.Update(user3); 

Bedeutet, dass Sie nur in einer Sache übergeben müssen und man kann es für was auch immer verwenden. Anstatt einige Repositories zu passieren. Stellt dich auch gut für das Unit Of Work-Muster ein.

+0

Nur zu beachten - wenn Sie die parameterlosen Konstruktoren loswerden, dann müssen Sie auch Ihre eigenen Controller-Fabriken rollen. – womp

+0

Warum Fabriken? Im obigen Fall injiziert das DI-Framework alles für Sie. Dinge wie ISessionHelper und IUserRepository sollten eine statische Sitzung ausführen und höchstwahrscheinlich keine Werte haben, die Sie übergeben möchten. Alles, was Sie tun müssen, ist Aufruf: var controller = IoC.Resolve () ; und es ist alles für dich gebaut. Injizieren über den Konstruktor bedeutet, dass Sie Variablen über Methodenparameter übergeben oder öffentliche Eigenschaften festlegen müssen (ähnlich wie das Befehlsmuster). – Bealer

Verwandte Themen