Search code examples
c#asp.netunit-testingasp.net-web-api2membership-provider

How should register my System.Web.Security.Membership to avoid this issue in the unit test of an API controller?


I created a unit test to a log in a user, using an api controller and the membership is checking the user that is in my Dto using this line of code.

  MembershipUser membershipUser = System.Web.Security.Membership.GetUser(Username);

On the web application this is working well, but on the test project and my unit test I am having this exception.

Access to the path 'C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 12.0\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\TESTWINDOW\App_Data' is denied.

How should register my System.Web.Security.Membership to avoid this issue in the unit test?

My test method looks like this:

  [TestMethod]
  public void LoginSuccessfullyAnUser()
  {
      //Arrange
      var controller = new TokensController(unitOfWork, unitOfWorkMembership, configManager);
      var credentials = new LoginUserDTO
                             { 
                                 Username = "user1", 
                                 Password = "12345678" 
                              };

      controller.Request = new HttpRequestMessage 
      {
           RequestUri = new Uri("http://localhost/api/tokens")
      };

      controller.Configuration = new HttpConfiguration();
      controller.Configuration.Routes.MapHttpRoute(name: "DefaultApi", 
                                         routeTemplate: "api/{controller}/{id}",
                                         defaults: new { id = RouteParameter.Optional });

      controller.RequestContext.RouteData = new HttpRouteData(route: new HttpRoute(),
                                                             values: new HttpRouteValueDictionary 
                                                                            { 
                                                                              { "controller", "tokens" } 
                                                                            });

      //Act
      var response = controller.Post(credentials);

      //Assert
      Assert.IsNotNull(response);
}

Solution

  • You will have to wrap Membership around a class e.g. MembershipService. All the membership API you are invoking will be redirected through this class. This basically give you the ability to mock the actual Membership class behavior in Unit Test.

    So let's see some code:

    Controller.cs

    [HttpPost]
    public JsonResult GetLoggedInUserName()
    {
        MembershipUser mem = _membershipService.GetUserDetails(User.Identity.Name);
    
        Guid membershipId = new Guid(mem.ProviderUserKey.ToString());
        var organizationUser = _organizationUserService.GetUserDetailsByMembershipId(membershipId);
        var  name = organizationUser.FirstName + " " + organizationUser.LastName;
    
        return Json(name);
    }
    

    MembershipService.cs

    public class MembershipService : IMembershipService
    {
        public MembershipUser GetUserDetails(string emailAddress)
        {
            return Membership.GetUser(emailAddress);
        }
    }
    

    MyTests.cs

        [TestMethod()]
        public void GetLoggedInUserName_InvokedWithValidSetup_ReturnUserName()
        {
            // Arrange
    
            // Setup membership to return mocked user
            var membershipService = new Mock<IMembershipService>();
    
            var user = new Mock<MembershipUser>();
            user.Setup(x => x.UserName).Returns("Adam");
            user.Setup(x => x.ProviderUserKey).Returns("1df03f8c-74fa-423a-8be8-61350b4da59f");
            user.SetupGet(x => x.Email).Returns("adamw@test.com");
    
            membershipService.Setup(m => m.GetUserDetails(It.IsAny<string>())).Returns(user.Object);
    
            // Setup organization user service - You can ignore it or replace
            // based on what you are using.
            var organizationUserService = new Mock<IOrganizationUserService>();
            var organizationUser = new OrganizationUser
            {
                FirstName = "Adam",
                LastName = "Woodcock",
                MembershipId = new Guid("1df03f8c-74fa-423a-8be8-61350b4da59f")
            };
            organizationUserService.Setup(s => s.GetUserDetailsByMembershipId(It.IsAny<Guid>())).Returns(organizationUser);
    
            var mock = new Mock<ControllerContext>();
            mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns("Adam");
            var target = GetTargetController(membershipService, null, organizationUserService, null, null);
            target.ControllerContext = mock.Object;
    
            // Act
            var result = target.GetLoggedInUserName();
    
            // Assert
            Assert.AreEqual(organizationUser.FirstName + " " + organizationUser.LastName, result.Data);
        }
    

    Hope this helps.