2

我有一个自定义成员资格提供程序,它连接到这样的用户存储库:

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

我正在为我的 DI 使用 ninject。现在我想测试提供者,并注入一个模拟用户存储库以允许我这样做。所以像:

        ... 
        IList<User> users = new List<User> {
            new User { Email="matt@test.com", 
                       UserName="matt@test.com", 
                       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

4

2 回答 2

3

由于您已将存储库作为属性公开,因此只需在测试类中创建提供程序的实例并将该属性设置为您的模拟,如下所示:

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

  // Do test stuff here

  // Verify mock conditions
}

大概您的存储库实现正在使用 UserRepository 属性,因此当您测试它时,此代码将使用模拟依赖项。

于 2013-08-22T18:08:13.820 回答
1

您可以为 Ninject 设置一个测试模块,并使用单元测试项目中的测试模块创建 Ninject 内核。

这就是控制容器反转的用途。您有一组绑定配置为作为网站运行,另一组用于在测试中运行,另一组用于使用不同的后端(或其他)运行。

我这样做是为了使生产和测试代码以相同的方式初始化(​​通过 Ninject),所有更改都是 Ninject 的配置。

或者按照@chris house 的建议去做。那也行。

于 2013-08-22T18:19:21.907 回答