Asp.net has a wonderful system built in for handling user accounts and roles. The administration interface is encapsulated in a separate web site that can be accessed from within Visual Studio but it is difficult to integrate into the site.  This often leads to building a new user administration area in each site.  The problem I have with this is going into the data store and deleting the incomplete test data and not having "known good" data for testing.

In the past, I have talked about provider pattern and the built is membership and roles systems both use providers.  This offers a wonderful framework for unit testing and more importantly for have a data store that reverts to a known good state every time the application is run.  

Enter the "dummy provider".  A dummy provider contains the data store in the code.  It is nothing more than a list of objects that is modified by the providers methods.  Because of this the data will revert to its initial state when it is run, it can be used without a SQL server (or some other data store) and the user interface can be tested by adding, deleting and modifying the data until your hearts content.   This makes testing and changing the user interface for membership and roles faster and easier; but the dummy provider is not limited to membership and roles. 

Lets look at the some code, the dummy role provider

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;

namespace CS.Data.Providers.Dummies
{
    public class DummyRoleProvider : RoleProvider
    {
        internal static List<string> _roles;
        internal static List<PersonToRole> _userToRole;
        internal class PersonToRole : IEqualityComparer<PersonToRole>
        {
            public PersonToRole(string user, string role)
            {
                _userName = user;
                _roleName = role;
            }
            private String _userName;

            public String UserName
            {
                get { return _userName; }
                set { _userName = value; }
            }
            private String _roleName;

            public String RoleName
            {
                get { return _roleName; }
                set { _roleName = value; }
            }

            #region IEqualityComparer<PersonToRole> Members

            public bool Equals(PersonToRole x, PersonToRole y)
            {
                return ((x._userName == y._userName) && (x._roleName == y._roleName));
            }

            public int GetHashCode(PersonToRole obj)
            {
                return base.GetHashCode();
            }

            #endregion
        }
        static DummyRoleProvider()
        {
            _roles = new List<string>();
            _roles.Add("Administrator");
            _roles.Add("Cat");
            _roles.Add("Customer");
            _roles.Add("User");

            _userToRole = new List<PersonToRole>();
            _userToRole.Add(new PersonToRole("Admin", "Cat"));
            _userToRole.Add(new PersonToRole("Admin", "User"));
            _userToRole.Add(new PersonToRole("Admin", "Administrator"));
            _userToRole.Add(new PersonToRole("Admin", "Customer"));

            _userToRole.Add(new PersonToRole("SomeCustomer", "Customer"));
            _userToRole.Add(new PersonToRole("SomeCustomer1", "Customer"));
            _userToRole.Add(new PersonToRole("SomeCustomer2", "Customer"));
            _userToRole.Add(new PersonToRole("Admin2", "Customer"));
            _userToRole.Add(new PersonToRole("Admin3", "Customer"));

            _userToRole.Add(new PersonToRole("SomeCustomer2", "User"));
            _userToRole.Add(new PersonToRole("Admin3", "User"));

            _userToRole.Add(new PersonToRole("SomeCustomer", "User"));
            _userToRole.Add(new PersonToRole("SomeCustomer1", "User"));

            _userToRole.Add(new PersonToRole("Admin2", "Administrator"));
            _userToRole.Add(new PersonToRole("Admin3", "Administrator"));

        }
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            foreach (string user in usernames)
            {
                foreach (string role in roleNames)
                {
                    PersonToRole ptr = new PersonToRole(user, role);
                    if (!_userToRole.Contains(ptr)) _userToRole.Add(ptr);
                }
            }
        }

        public override string ApplicationName { get; set; }

        public override void CreateRole(string roleName)
        {
            if (!_roles.Contains(roleName)) _roles.Add(roleName);
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            if (_roles.Contains(roleName))
            {
                _userToRole = _userToRole.Where(p => p.RoleName != roleName).ToList();
                _roles.Remove(roleName);
                return true;
            }
            else
            {
                return false;
            }
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            return _userToRole.Where(p => p.RoleName == roleName).Select(u => u.UserName).ToArray();
        }

        public override string[] GetAllRoles()
        {
            return _roles.ToArray();
        }

        public override string[] GetRolesForUser(string username)
        {
            return _userToRole.Where(p => p.UserName == username).Select(r => r.RoleName).ToArray();
        }

        public override string[] GetUsersInRole(string roleName)
        {
            return _userToRole.Where(p => p.RoleName == roleName).Select(u => u.UserName).ToArray();
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            return _userToRole.Contains(new PersonToRole(username,roleName));
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            foreach (string user in usernames)
            {
                foreach (string role in roleNames)
                {
                    PersonToRole p = new PersonToRole(user, role);
                    if (_userToRole.Contains(p)) _userToRole.Remove(p);
                }
            }
        }

        public override bool RoleExists(string roleName)
        {
            return _roles.Contains(roleName);
        }
    }
}

First you may notice there are 2 lists inside the provider.  One is just a list of strings.  because the asp.net role system treats roles as nothing more than a string the dummy provider does not need to hang onto any extra data.  The second list is holds onto a PersonToRole object.  The PersonToRole object just holds the username and role. 

Using the provider is as easy as configuring the web.config to look at the dummy provider instead of the data provider

The user membership provider has a bit more too it.  Again there is a private class that defines the user that is stored in the list.  The providers constructor creates several users and stores them in an internal list.

In the constructor there is a list of names that is used to create the user accounts.  To add the account to a specific role simply add the user name and role to the role providers constructor.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using CS.People;
using CS.Identifiers;

namespace CS.Data.Providers.Dummies
{
    public class DummyMembershipProvider : MembershipProvider
    {
        private class myUser
        {
            #region security fields for asp.net member and roles

            private string _email = String.Empty;

            public string Email
            {
                get { return _email; }
                set { _email = value; }
            }
            private String _comments = String.Empty;

            public String Comments
            {
                get { return _comments; }
                set { _comments = value; }
            }

            private bool _isApproved=true;

            public bool IsApproved
            {
                get { return _isApproved; }
                set { _isApproved = value; }
            }

            private bool _isLocked=false;

            public bool IsLocked
            {
                get { return _isLocked; }
                set { _isLocked = value; }
            }

            private DateTime _created = DateTime.Now;

            public DateTime CreatedDate
            {
                get { return _created; }
                set { _created = value; }
            }
            private DateTime _login = DateTime.Now;

            public DateTime LastLoginDate
            {
                get { return _login; }
                set { _login = value; }
            }

            private DateTime _lastActivity = DateTime.Now;

            public DateTime LastActivityDate
            {
                get { return _lastActivity; }
                set { _lastActivity = value; }
            }
            private DateTime _lastPasswordChange = DateTime.Now;

            public DateTime LastPasswordChangeDate
            {
                get { return _lastPasswordChange; }
                set { _lastPasswordChange = value; }
            }

            private DateTime _lastLock=DateTime.Now;

            public DateTime LastLockDate
            {
                get { return _lastLock; }
                set { _lastLock = value; }
            }
            private string _passwordQuestion = String.Empty;

            public string PasswordQuestion
            {
                get { return _passwordQuestion; }
                set { _passwordQuestion = value; }
            }

            private string _passwordAnswer=String.Empty;
            /// <summary>
            /// Used only by the dummy provider for testing
            /// </summary>
            public string PasswordAnswer
            {
                get { return _passwordAnswer; }
                set { _passwordAnswer = value; }
            }
            private string _password = String.Empty;
            /// <summary>
            /// Used only by the dummy provider for testing
            /// </summary>
            public string Password
            {
                get { return _password; }
                set { _password = value; }
            }

            private string _userName = String.Empty;
            public string UserName
            {
                get { return _userName; }
                set { _userName = value; }
            }

            private Guid _id=Guid.Empty;

            public Guid Id
            {
                get { return _id; }
                set { _id = value; }
            }

            private bool _isOnline;

            public bool IsOnline
            {
                get { return _isOnline; }
                set { _isOnline = value; }
            }

            #endregion


        }
        private static Dictionary<string, myUser> _users;
        static DummyMembershipProvider()
        {
            _users = new Dictionary<string, myUser>();

            List<string> names = new List<string>{"Administrator","User", "Bob", "Ed","George", "Frank",
                "Admin", "SomeCustomer1", "SomeCustomer"};
            int i = 0;
            foreach (string name in names)
            {
                i++;
                CreateUser(name, "password", name + "@someplace.com", "What is my name?", name, (i % 2) == 0, Guid.NewGuid());
            }
        }
        public override string ApplicationName { get; set; }

        private MembershipUser GetMembershipUser(myUser p)
        {
            return new MembershipUser(this.Name, p.UserName, p.Id, p.Email, p.PasswordQuestion, p.Comments
                , p.IsApproved, p.IsLocked, p.CreatedDate, p.LastLoginDate, p.LastActivityDate, p.LastPasswordChangeDate
                , p.LastLockDate);
        }

        public override bool ChangePassword(string username, string oldPassword, string newPassword)
        {
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == username);
            if (u == null) return false;
            if (u.Password == oldPassword)
            {
                u.Password = newPassword;
            }
            else
            {
                return false;
            }
            return true;
        }

        public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == username);
            if (u == null) return false;
            if (u.Password != password)
            {
                return false;
            }
            else
            {
                u.PasswordAnswer = newPasswordAnswer;
                u.PasswordQuestion = newPasswordQuestion;
            }
            return true;
        }

        private static myUser CreateUser(string username, string password, string email
            , string passwordQuestion, string passwordAnswer, bool isApproved
            , object providerUserKey)
        {
            myUser m = new myUser();
            m.UserName = username;
            m.Password = password;
            m.Email = email;
            m.PasswordQuestion = passwordQuestion;
            m.PasswordAnswer = passwordAnswer;
            m.IsApproved = isApproved;
            if (providerUserKey != null && providerUserKey is Guid)
                m.Id = (Guid)providerUserKey;
            else
                m.Id = Guid.NewGuid();

            _users.Add(m.UserName, m);
            return m;

        }
        public override MembershipUser CreateUser(string username, string password, string email
            , string passwordQuestion, string passwordAnswer, bool isApproved
            , object providerUserKey, out MembershipCreateStatus status)
        {
            status = MembershipCreateStatus.Success;
            myUser m = CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey);

            if (_users.Values.FirstOrDefault(u => u.UserName == m.UserName) != null) status = MembershipCreateStatus.DuplicateUserName;
            if (_users.Values.Count(u => u.Email == email) > 0) status = MembershipCreateStatus.DuplicateEmail;
            if (_users.Values.Count(u => u.Id == m.Id) > 0) status = MembershipCreateStatus.DuplicateProviderUserKey;
            if (status == MembershipCreateStatus.Success) _users.Add(m.UserName, m);
            return GetMembershipUser(m);
        }

        public override bool DeleteUser(string username, bool deleteAllRelatedData)
        {
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == username);
            if (u == null) return false;
            u.IsApproved = false;
            u.Comments += "/r/nDeleted";
            return true;
        }

        public override bool EnablePasswordReset
        {
            get { return true; }
        }

        public override bool EnablePasswordRetrieval
        {
            get { return true; }
        }

        public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection c = new MembershipUserCollection();
            totalRecords = _users.Count;
            List<myUser> usersFound = _users.Values.Where(u => u.Email.ToLower().Contains(emailToMatch.ToLower())).ToList();
            foreach (MembershipUser m in usersFound.Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(u => GetMembershipUser(u)))
            {
                c.Add(m);
            }
            return c;
        }

        public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection c = new MembershipUserCollection();
            totalRecords = _users.Count;
            List<myUser> usersFound = _users.Values.Where(u => u.UserName.ToLower().Contains(usernameToMatch.ToLower())).ToList();
            foreach (MembershipUser m in usersFound.Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(u => GetMembershipUser(u)))
            {
                c.Add(m);
            }
            return c;
        }

        public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection c = new MembershipUserCollection();
            totalRecords = _users.Count;
            foreach (MembershipUser m in _users.Skip((pageIndex - 1) * pageSize).Take(pageSize).Select(u => GetMembershipUser(u.Value)))
            {
                c.Add(m);
            }
            return c;
        }

        public override int GetNumberOfUsersOnline()
        {
            return _users.Values.Where(u => u.IsOnline).Count();
        }

        public override string GetPassword(string username, string answer)
        {
            string result = "";
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == username);
            if (u != null)
            {
                if (u.PasswordAnswer == answer) result = u.PasswordAnswer;
            }
            return result;
        }

        public override MembershipUser GetUser(string username, bool userIsOnline)
        {
            MembershipUser result = null;
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == username);
            if (u != null)
            {
                u.IsOnline = userIsOnline;
                result = GetMembershipUser(u);
            }
            return result;
        }

        public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
        {
            MembershipUser result = null;
            myUser m = _users.Values.FirstOrDefault(u => u.Id == (Guid)providerUserKey);
            if (m != null)
            {
                m.IsOnline = userIsOnline;
                result = GetMembershipUser(m);
            }
            return result;
        }

        public override string GetUserNameByEmail(string email)
        {
            string result = "";
            myUser u = _users.Values.FirstOrDefault(m => m.Email == email);
            if (u != null) result = u.UserName;
            return result;
        }

        public override int MaxInvalidPasswordAttempts
        {
            get { return 3; }
        }

        public override int MinRequiredNonAlphanumericCharacters
        {
            get { return 0; }
        }

        public override int MinRequiredPasswordLength
        {
            get { return 4; }
        }

        public override int PasswordAttemptWindow
        {
            get { return 5; }
        }

        public override MembershipPasswordFormat PasswordFormat
        {
            get { return MembershipPasswordFormat.Clear; }
        }

        public override string PasswordStrengthRegularExpression
        {
            get { return ""; }
        }

        public override bool RequiresQuestionAndAnswer
        {
            get { return true; }
        }

        public override bool RequiresUniqueEmail
        {
            get { return false; }
        }

        public override string ResetPassword(string username, string answer)
        {
            string result = "";
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == username);
            if ((u != null) && (u.PasswordAnswer == answer))
            {
                result = "password1";
                u.Password = result;
            }
            return result;
        }

        public override bool UnlockUser(string userName)
        {
            bool result = false;
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == userName);
            if (u != null)
            {
                u.IsLocked = false;
            }
            return result;
        }

        public override void UpdateUser(MembershipUser user)
        {
            myUser m = _users.Values.FirstOrDefault(u => u.UserName == user.UserName);
            m.Comments = user.Comment;
            m.Email = user.Email;
            m.IsApproved = user.IsApproved;
            m.IsLocked = user.IsLockedOut;
            m.LastActivityDate = user.LastActivityDate;
            m.LastLockDate = user.LastLockoutDate;
            m.LastLoginDate = user.LastLoginDate;
            m.LastPasswordChangeDate = user.LastPasswordChangedDate;
            m.PasswordQuestion = user.PasswordQuestion;
        }

        public override bool ValidateUser(string username, string password)
        {
            bool result = false;
            myUser u = _users.Values.FirstOrDefault(m => m.UserName == username);
            if ((u != null) && (u.Password == password))
                result = true;
            return result;

        }
    }
}

There is always room for improvement; for example some settings could be taken from the web.config instead of code.  The dummy provider allows direct control of test data at the start of the application which allows unit tests to be created that are not dependant on a database.