Testing a Membership Provider
Here’s something that I was toying with yesterday: creating a MembershipProvider that does all it’s storage in-memory. This would be used in "test-only" situations where you can’t run against a "real" provider. Should be easy, right? I mean, this provider barely does anything. Instead, we end up needing various source views, a few different membership classes, and some reflection.
First Task: MembershipProvider.CreateUser
There is some logic involved in maintaining the in-memory information, and I certainly don’t want to have to run a web application to test the functionality as I’m building it, so the first thing is to create a ".Test" assembly.
My first test for creating a MembershipUser looked something like this:
[Test] public void CreateUser() { // this is what we’re testing: var provider = new VirtualMembershipProvider(); // creation of all of these args omitted for brevity.. var user = provider.CreateUser(…); // verify that the MembershipUser is valid.. Assert.AreEqual(user.UserName, userName); // etc.etc.etc. }
And the implementation of VirtualMembershipProvider.CreateUser(): (obviously I’m leaving out some unimportant details..)
public override MembershipUser CreateUser(…) { // MembershipUser takes crazy big number of args.. MembershipUser user = new MembershipUser(…); // TODO: put that user object somewhere for later access.. status = MembershipCreateStatus.Success; return user; }
Can’t get much simpler, right?
First Issue - Arbitrary Dependency
Running the test gives an exception from the MembershipUser constructor: "System.ArgumentException : The membership provider name specified is invalid." So, we jump over to Reflector to see what’s going on:
if ((providerName == null) || (Membership.Providers[providerName] == null)) { throw new ArgumentException(…); }
MembershipUser has a dependency on Membership.Providers. This is because MembershipUser is not just a data container, but breaks the Single Responsibility Principle (SRP) and has methods like Update() as well. But, whatever. Looks like all I’ve got to do is add my VirtualMembershipProvider into that Membership.Providers collection, and we’ll be set.
Next Issue - Arbitrary ReadOnly-ness
I put "Membership.Providers.Add()" into the test, to see what happens. Running the test gives me a new exception: in ProviderCollection.Add() - "System.NotSupportedException : Collection is read-only." Argh! Back to Reflector! Here’s what ProviderCollection.Add() looks like (more or less):
public virtual void Add(ProviderBase provider) { if (this._ReadOnly) throw new NotSupportedException(…); // some other guard clauses… this._Hashtable.Add(provider.Name, provider); }
So all I’ve got to do is call ".IsReadOnly = false" and… ha ha jokes on me. ProviderCollection has a SetReadOnly() method, but no public way to switch readonly-ness off. Presumably there’s some really good reason for making things difficult with this totally artificial wall that they put in our path.
So, we fall back to the tool of last resort: reflection to get that private _ReadOnly field and set it to false. Now we can register our provider into the ProviderCollection. But, what an ugly hack, for seemingly no reason.
One more thing lacking: before the ProviderCollection will accept a Provider, it checks to see if the Provider has been initialized properly. So we need a call to provider.Initialize() which sets some internal state on the provider.
(Note: by this point, we actually have a fair amount of initialization code here, and its getting complicated. So this code was moved into its own class & tests - I’ve left that part out to be more concise.)
More or less, we’ve got this code to set up our MembershipProvider, outside of the official procedures:
public static void Initialize(MembershipProvider provider, string providerName) { provider.Initialize(providerName, null); // grabs a cached FieldInfo instance and sets it appropriately. // note this would affect all Membershp providers… AllowNewProviders = true; Membership.Providers.Add(provider); }
And now, our CreateUser() test passes and we can get back to work on the REAL problem.
Conclusions
- Don’t put arbitrary roadblocks in your framework. You have no idea how somebody will need to use (and abuse) it.
- Strive to keep your code decoupled. Always a good idea no matter what you’re working on.
- This is "running with scissors:" I wouldn’t propose subverting the Provider model with this sort of hackery for code that you wanted to use in production, at least not with much more testing and consideration. There might be (and probably is) a really good reason for that _ReadOnly flag, and we just broke it..
- And to bring us back to the first point: framework developers should provide the "default safe" implementation with that _ReadOnly flag, but then at least provide a way to cleanly get around the safety mechanism, for those of us who are willing to accept the risk.
So, ASP.NET, thanks for the offer of holding my hand through every step of the way, but instead how about you just get out of my way and let me get my work done, kthxbai.
Filed under: Uncategorized





Membership.Providers is a run-time collection representing the configured providers for that system. It is made read-only so it can be initialized and then let loose in the wild.
The solution here is to configure your provider in App.config so it falls neatly into the initialization pipeline.
Conclusions:
* Don’t assume roadblocks are arbitrary. It is most likely there to prevent abuse in the first place.
* Be sure to investigate the standard ways of accomplishing your goal before “just getting it done” - be sensitive to intent vs. mechanism.
Ah, but I don’t want to configure it from App.config, because I’m driving this particular initialization from unit tests.
I agree that a typical usage of a provider would be through the standard configuration mechanism. But the provider doesn’t give us a mechanism for following an alternative other than typical.
If there’s a standard way for initializing membership providers in a unit test scenario, aside from some sort of hack involving multiple app.configs overloaded at run-time, I’d love to hear it.
Also - just to be clear - the initialization procedures here are to set up unit tests *developing the provider itself* - and not meant for consumers of the provider. They’d use app.config and the standard initialization pipeline as normal.
That’s why I can override the _ReadOnly field and not worry about what else that is going to break. You wouldn’t do that “for real.”
[...] Testing a Membership Provider - Tony Rasa looks at creating an in memory Membership provider for test use. [...]
App.config is the authority on the state of the framework running underneath your application. An app domain running a unit test is no different from a web app, Forms app, console app, or Windows service, from the perspective of the configuration system.
That is why there is a direct, immutable dependency on that system. It is *the* way to do what you seek to do. Any other approach is proprietary, introduces an unnecessary dichotomy, and most likely won’t scale.
Your unit testing framework should have a way to load an App.config. If you need to test multiple providers of a system, you may register several and refer to each by name.
Also, to be clear: your unit testing framework should support a way to load App.config which is not a manual build step, i.e. done automatically like in ASP.NET and Forms projects.
For example, a Google search of “nunit app.config” has this as the first result:
http://www.cornetdesign.com/2005/08/nunit-appconfig-files-its-all-about.html
You can tell your NUnit project the name of the configuration file; it will be loaded when the app is run, and reloaded with rebuilt DLLs.
_ReadOnly, in this case, is akin to a thin metal ruler:
http://blogs.msdn.com/ericlippert/archive/2003/11/03/53333.aspx
Adding a new line to the providers block for each test in the test app.config doesn’t strike me as scalable at all - and to test individual parts of this provider, i need the ability to unload & reload “fresh” copies of it. so the immutable dependency is exactly the problem.
I think you’re confusing consuming the provider with testing the provider itself. I’m not talking about writing unit tests for a web application that also uses membership provider, I’m talking about writing unit tests for developing the provider itself.
This doesn’t allow me to meet the testing requirements of writing code like (apologies for this being all munged up):
[Test] public void CreateValidUser() {
VirtualMembershipProvider provider = new VirtualMembershipProvider();
MembeshipUser testResult = provider.CreateUser(….);
}
Microsoft has had a hostile approach towards TDD and alternative approaches in general; for more evidence of that just google for anything “ALT.Net”.
I didn’t mean that you should register a provider per test - I meant that you should register all implementations that need to be tested. In your case, there is only 1 implementation, VirtualMembershipProvider, and that provider is the sole target of your test suite.
The same set of tests could be applied to another provider by registering it under a new name. You can target an entirely new implementation with the same tests using this technique. You end up with a line in the provider block per implementation, not per test.
A provider can be considered a pluggable implementation of an API. It is not meant to be stateful, i.e. requiring a “fresh” instance for each test. The only state in a provider is its configuration, which is scoped to all operations. If you need to test a different configuration, you now have a new implementation to register.and refer to.
What you are seeking to test is the particular implementation of an API represented by your provider. As such, you should be using the API to test, and ensure that API is hooked up to the correct implementation, not bypass it completely.
Consuming the provider and testing it are synonymous in a unit test.