So as usual with so many of .NET 1.0 to .NET 2.0 era classes, Microsoft have made it near impossible to mock out MembershipProvider. The MembershipProvidersCollection class is read-only so you can’t just add your own provider at runtime.

No matter! After some time with Reflector and some twiddling with reflection I came up with a way to add a mocked out MembershipProvider.

        public static void AddMembershipProvider(this ProviderCollection providers, string providerName, MembershipProvider provider)
        {
            GetMembershipHashtable().Add(providerName, provider);
        }

        public static void RemoveMembershipProvider(this ProviderCollection providers, string providerName)
        {
            GetMembershipHashtable().Remove(providerName);
        }

        static Hashtable GetMembershipHashtable()
        {
            var hashtableField = typeof(ProviderCollection).GetField("_Hashtable", BindingFlags.Instance | BindingFlags.NonPublic);
            return hashtableField.GetValue(Membership.Providers) as Hashtable;
        }

I then called the above methods from my SetUp and TearDown methods so as to ensure the next test doesn’t run with the same providers. I’m using Moq to generate the mocks in the example code below:

        private Mock _membership;
        private MockFactory _factory;

        [SetUp]
        public override void Setup()
        {
            _factory = new MockFactory(MockBehavior.Strict);
            _membership = _factory.Create();
            Membership.Providers.AddMembershipProvider("MyMembershipProvider", _membership.Object);
        }

        [TearDown]
        public override void Teardown()
        {
            Membership.Providers.RemoveMembershipProvider("MyMembershipProvider");
        }

I know you’re not supposed to access private variables blah blah because they can change blah blah break your code blah blah blah but I don’t care. The code is all in one place and my unit tests are part of my continuous build. If Microsoft happen to decide to change the implementation, I should get a notification from TeamCity as soon as I upgrade. In the meantime, I’ll be happily unit testing my code.