2009-09-17 63 views
6

爲了能夠構造測試用例,我已經實現了使用依賴注入模式的名爲DefaultController的mvc基礎控制器。下面的例子:如何解決基礎控制器依賴注入測試的目的?

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; 
    } 
} 

然後,我必須使用這種控制器,HomeController中,UserController的我控制器等

現在,建設一些測試情況下,我發現自己在一個情況下,我不知道如何實際使用注入依賴模式。

[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(); 

任何想法?

回答

5

你的HomeController需要有一個匹配的「injectable」構造函數,然後調用基礎構造函數。現在

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

    } 

,在您的測試,你會使用構造函數創建HomeController中,並通過在嘲笑了會話和用戶信息庫。說到嘲笑,你可能也會對Scott Hanselman's MvcMockHelpers classes感興趣,並且有許多流行的嘲笑框架的代碼。

3

我不明白你爲什麼有兩個構造函數。你應該只有一個,擺脫沒有參數的構造函數。使用像Castle Windsor這樣的DI框架或我的首選框架,Autofac將爲您處理所有這些問題。然後就測試而言,使用Moq之類的東西。即

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

在您的DI框架中註冊DefaultController,ISessionHelper和IUserRepository。沿線的東西:

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

這樣,你可以從容器中拉出DefaultController,DI框架會爲你注入兩個參數。我包裝了一個靜態方法來訪問我的DI容器,它看起來像:

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

基本上轉到Autofac並看看。還有一個用於爲您註冊控制器的Web模塊。

然後爲了測試只使用Moq,或找到某種形式的「AutoMocker」(谷歌它)。我會這樣做:

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(); 

此外ewww版本庫。使用.Net和泛型等......只需創建一個不錯的ISession。

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

意味着你只需要傳遞一件東西,你可以用它來做任何事情。而不是必須有時傳入許多存儲庫。也爲您的單位工作模式設置得很好。

+0

只需注意 - 如果您擺脫了無參數的構造函數,那麼您還需要推出自己的控制器工廠。 – womp 2009-09-18 00:05:17

+0

爲什麼選擇工廠?在上面的例子中,DI框架爲您注入了一切。類似ISessionHelper和IUserRepository的應該運行一個靜態會話,並且很可能不會有任何想要傳入的值。 所有你需要做的就是調用: var controller = IoC.Resolve () ;這一切都是爲你而建。 通過構造函數注入意味着您必須通過via方法參數傳遞變量,或者設置公共屬性(很像命令模式)。 – Bealer 2009-09-18 07:24:42