問題描述
模擬會員 (Mocking Membership)
I'm writing a custom Profile provider, but I still intend to use the default AspNetSqlMembershipProvider as my Membership provider. My GetAllProfiles() method in my Profile provider looks like this:
1 public override ProfileInfoCollection GetAllProfiles(ProfileAuthenticationOption authenticationOption, int pageIndex, int pageSize, out int totalRecords)
2 {
3 // Get the profiles
4 IQueryable<Profile> profiles = _profileRepository.GetAllProfiles();
5
6 // Convert to a ProfileInfoCollection
7 ProfileInfoCollection profileInfoCollection = new ProfileInfoCollection();
8 foreach (Profile profile in profiles)
9 {
10 MembershipUser user = Membership.GetUser(profile.UserId);
11
12 string username = user.UserName;
13 bool isAnonymous = false;
14 DateTime lastActivity = user.LastActivityDate;
15 DateTime lastUpdated = profile.LastUpdated;
16
17 ProfileInfo profileInfo = new ProfileInfo(username, isAnonymous, lastActivity, lastUpdated, 1);
18
19 profileInfoCollection.Add(profileInfo);
20 }
21
22 // Set the total number of records.
23 totalRecords = profiles.ToList().Count;
24
25 return profileInfoCollection;
26 }
How do I mock the Membership.GetUser() call so that I can write tests for this method? Any suggestions or examples? Thanks.
參考解法
方法 1:
I'm running into this problem as well
the problem lies in the fact that the method GetUser() without parameters is implemented as a static method on the class.
Whereas the Membership.Provider (when mocked) does not contain a GetUser() method without parameters.
By the way here is how I fixed this problem. I encapsulated the static call in my own class which implements an interface so it can be mocked.
public interface IStaticMembershipService
{
MembershipUser GetUser();
void UpdateUser(MembershipUser user);
}
public class StaticMembershipService : IStaticMembershipService
{
public System.Web.Security.MembershipUser GetUser()
{
return Membership.GetUser();
}
public void UpdateUser(MembershipUser user)
{
Membership.UpdateUser(user);
}
}
方法 2:
Could you inject a MembershipProvider
instance into your profile provider and, if none is injected, fall back on using Membership.Provider
?
public MembershipProvider MembershipProvider
{
get { return _membershipProvider ?? Membership.Provider; }
set { _membershipProvider = value; }
}
Your profile provider would interact with the membership provider through the value returned by this property. In your test you'd inject the fake/mock MembershipProvider
instance.
If you instead want to just mock the static methods on Membership, you'll have to use something like TypeMock, I guess.
方法 3:
In ASP.NET MVC they solved this by encapsulating (wrapping) the membership functionality in a MebershipService. Which (for instance: through injection) you can then easily mock in your tests.
An example of mocking services... http://www.asp.net/learn/mvc/tutorial-30-cs.aspx they don't use injection though.
A nice example is actually the test project generated when you create an ASP.NET application. In the following code you can see how they mock The FormsAuthentication and Membership objects:
[TestMethod]
public void ConstructorSetsProperties()
{
// Arrange
IFormsAuthentication formsAuth = new MockFormsAuthenticationService();
IMembershipService membershipService = new AccountMembershipService();
// Act
AccountController controller = new AccountController(formsAuth, membershipService);
// Assert
Assert.AreEqual(formsAuth, controller.FormsAuth, "FormsAuth property did not match.");
Assert.AreEqual(membershipService, controller.MembershipService, "MembershipService property did not match.");
}
(by Rob Abernethy、Sjors Miltenburg、Dave Cluderay、Cohen)