Search code examples
c#unit-testingninjectmoqmembership-provider

Unit testing my custom membership provider


I have a custom membership provider which connects to a user repository like this:

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

I am using ninject for my DI. Now I would like to test the provider, and have a mock user repository injected to allow me to do this. So something like:

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

And here is where I am not certain how to proceed, how do I get my mocked repository injected into my provider so that when a unit test that makes calls to the provider uses this mock repository?

Am I asking the right questions here?

EDIT - My final solution

For what it is worth I moved away from using mock to using an InMemory repository to maintain state so the provider would properly test certain functions. Right now I am only using this to test things like my provider. I ended up with:

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

Then my actual user repository - I do not have generic ID fields which is why I am using the IDPropertyName variable:

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

My membership test base class:

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

Then my test:

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

This answer provided inspiration: https://stackoverflow.com/a/13073558/1803682


Solution

  • Since you've exposed your repository as a property, just create an instance of your provider in your test class and set that property to your mock like so:

    public void Test()
    {
      MyMembershipProvider provider = new MyMembershipProvder();
      provider.UserRepository = mock.Object;
    
      // Do test stuff here
    
      // Verify mock conditions
    }
    

    Presumably your repository implementation is using the UserRepository property so when you test it, this code will use the mocked dependency.