My team and I have been happily using ASP.Net Membership alongside Forms Authentication to provide authenticated access to private areas of our with zero problems. We have been using the default Sql Server storage, which was a walk in the park after fighting against custom Active Directory access and its security issues.
We have been also using User Profiles for storing information about our users. Thanks to the extensibility of the provider model (and I am not going to rant on its implementation, SRP and God-Like classes), we used a different provider to store the data in plain-old tables, instead of the default serialized-blob-style provider, as we needed some sort of reporting on that data outside the application.
Our application are developed using Web Applications projects, instead of Web Site projects, which leave us with no runtime generation of strongly typed profile classes. Not a big deal and provides us with quite a bit of flexibility.
With this background in mind I will proceed to explain how we have used the profile system and how we managed to test the code surrounding it.
This first part will be about the profile class itself. This class is used merely to extract information from the profile system. The domain object that we use to represent our users is a different one. One that provides behaviour and has its data populated from more than one data source, one of which is this profile class we are talking about now. Think about this class as some sort of Active Record class whose data storage is the Asp.NET profile system.
This class wraps the System.Web.Profile.ProfileBaseClass and provides access to their properties. It is very simple in its conception and its potential complexity comes solely from the complexity and the format of the data to be stored.
The only thing that stands up a bit are the virtual methods, which wrap the calls to the profile infrastructure and will be used to mock behaviour when testing.
But… it is a data class with no behaviour at all. Why do would anyone want to waste time on testing a wrapper on top of a framework class? Well, if all properties were like the Id property, it would be indeed a waste of time. But what happens when some properties are not direct mappings? What happens when we have, for example, a property that maps to a nullable enumeration or to a value object? In that case, we surely want to test upfront that our mapping around the data is done correctly even in the edge cases (specially in the edge cases), don’t we? And those are the cases we faced and that lead me to write this entry.
Ok, let’s start with the “waste of time”, but we are starting with the easy bits: a direct mapping of a property.
Simple test that uses the ability of Rhino.Mocks to mock a concrete classes, as long as the members being mocked are virtual. The point to be proved is that the property value is get and set from the profile system directly, hence the consistency of the behaviour does not matter.
But when we run the test we get a shocking fail:
The GetProperty<>() method is being called despite the expectations set. Why? The answer lies in the accessibility of the methods being mocked. Rhino.Mocks cannot mock an internal property… without help. So we will help the framework a bit by allowing it access to internal properties by making the mock assembly a “friend” of this assembly. We accomplish that using the InternalsVisibleToAttribute inside the AssemblyInfo.cs of the project:
Which will make the test bright green the next time we run it.
The interesting bits, the ones that that justify the existence of test i the first place follow the same strategy of setting the expectations and exercising setting and retrieving the property. We will only show the tests related to Gender, but of course the rest of tests can be reviewed in
As we can see it is a very simple class to test once the “problematic” calls (GetProperty<>() and SetProperty<>()) get mocked to model the different test cases.
The next part will be more interesting, from the testing techniques point of view, when we see how to test the class that uses this wrapper of the profile class.