2013-08-22 35 views
2

我有一個連接到這樣的用戶信息庫的自定義成員提供:單元測試我自定義的成員提供

public class MyMembershipProvider : MembershipProvider { 
    [Inject] 
    public IUserRepository UserRepository { get; set; } 
    ... 
    //Required membership methods 
} 

我使用ninject我的DI。現在我想測試提供程序,並注入一個模擬用戶存儲庫以允許我執行此操作。因此,像:

 ... 
     IList<User> users = new List<User> { 
      new User { Email="[email protected]", 
         UserName="[email protected]", 
         Password="test" 
      } 
     }; 
     var mock = new Mock<IUserRepository>(); 

     mock.Setup(mr => mr.FindByUsername(
      It.IsAny<string>())).Returns((string s) => users.Where(
      x => x.UserName.Equals(s,StringComparison.OrdinalIgnoreCase)).Single()); 
     ... 

而且這裏是我不能肯定如何着手,如何讓我的嘲笑庫注入到我的供應商,這樣,當一個單元測試,將調用提供者使用這種模擬庫?

我在這裏問正確的問題嗎?

編輯 - 我的最終解決方案

對於什麼是值得我用從模擬到使用InMemory庫,以保持狀態,這樣的供應商將正確測試某些功能搬走。現在我只用這個來測試像我的提供者這樣的東西。我結束了:

通用InMemoryRepository:

class InMemoryRepository<TEntity> : IRepository<TEntity> where TEntity : class { 
    private int _incrementer = 0; 
    public Dictionary<int, TEntity> List = new Dictionary<int, TEntity>(); 
    public string IDPropertyName {get; set;} 

    public void Create(TEntity entity) { 
     _incrementer++; 
     entity.GetType().GetProperties().First(p => p.Name == IDPropertyName).SetValue(entity, _incrementer, null); 
     List.Add(_incrementer,entity); 
    } 

    public TEntity GetById(int id) { 
     return List[id]; 
    } 

    public void Delete(TEntity entity) { 
     var key = (int)entity.GetType().GetProperties().First(p => p.Name == IDPropertyName).GetValue(entity, null); 
     List.Remove(key); 
    } 

    public void Update(TEntity entity) { 
     var key = (int)entity.GetType().GetProperties().First(p => p.Name == IDPropertyName).GetValue(entity, null); 
     List[key] = entity; 
    } 
} 

然後我的實際用戶信息庫 - 我沒有通用的ID字段這就是爲什麼我使用的IDPropertyName變量:

class InMemoryUserRepository : InMemoryRepository<User>, IUserRepository { 
    public InMemoryUserRepository() { 
     this.IDPropertyName = "UserID"; 
    } 

    public IQueryable<User> Users { 
     get { return List.Select(x => x.Value).AsQueryable(); } 
    } 

    public User FindByUsername(string username) { 
     int key = List.SingleOrDefault(x=>x.Value.UserName.Equals(username, StringComparison.OrdinalIgnoreCase)).Key; 
     return List[key]; 
    } 
} 

我會員測試基類:

[TestClass] 
public class MyMembershipProviderTestsBaseClass : IntegrationTestsBase { 
    protected MyMembershipProvider _provider; 
    protected NameValueCollection _config; 
    protected MembershipCreateStatus _status = new MembershipCreateStatus(); 

    [TestInitialize] 
    public override void Initialize() { 
     base.Initialize(); 

     // setup the membership provider 
     _provider = new MyMembershipProvider(); 

     MembershipSection section = (MembershipSection) ConfigurationManager.GetSection("system.web/membership"); 
     NameValueCollection collection = section.Providers["MyMembershipProvider"].Parameters; 
     _provider.Initialize(null, collection); 
     _status = new MembershipCreateStatus(); 
    } 

    [TestCleanup] 
    public override void TestCleanup() { 
     base.TestCleanup(); 
    } 
} 

然後我的測試:

[TestMethod] 
    public void Membership_CreateUser() { 
     _provider.UserRepository = new InMemoryUserRepository(); 
     _provider.CreateUser(_email, out _status); 
     Assert.AreEqual(MembershipCreateStatus.Success, _status); 
    } 

這個答案提供了靈感:https://stackoverflow.com/a/13073558/1803682

回答

3

既然你已經暴露你的倉庫作爲屬性,只需在您的測試類創建提供程序的實例和屬性設置爲你的模擬像這樣:

public void Test() 
{ 
    MyMembershipProvider provider = new MyMembershipProvder(); 
    provider.UserRepository = mock.Object; 

    // Do test stuff here 

    // Verify mock conditions 
} 

推測您的存儲庫實現使用UserRepository屬性,因此當您測試它時,此代碼將使用模擬的依賴關係。

+0

我很專注於讓它注入我並沒有停下來考慮明顯。無論如何,最終不得不放棄嘲笑 - 並創建內存中的存儲庫,以保留狀態並測試提供者。謝謝! – Matthew

1

您可以爲Ninject設置測試模塊,並使用單元測試項目中的測試模塊創建Ninject內核。

這是控制容器的反轉。你有一組綁定被配置爲作爲網站運行,另一組運行在測試中,另一組運行使用不同的後端(或其他)。

我這樣做,以便生產和測試代碼以相同的方式(通過Ninject)進行初始化,所有更改都是Ninject的配置。

或者做什麼@chris房子建議。這也會起作用。

相關問題