0

CustomMembershipProvider를 통해 데이터베이스 액세스가 필요한 단위 테스트를 작성합니다.단위 테스트에서 CustomMembershipProvider가 작동하지 않습니다.

edit -

public class CustomMembershipProvider : MembershipProvider 
    { 
     public override bool ValidateUser(string username, string password) 
     { 

      using (var usersContext = new UsersContext()) 
      { 
       var requiredUser = usersContext.GetUser(username, password); 
       var userApproved = usersContext.GetUserMem(username); 
       if (userApproved == null) return false; 
       return (requiredUser != null && userApproved.IsApproved != false); 
      } 
     } 
    } 

    [TestFixture] 
    public class AccountControllerTest 
    { 

     [Test] 
     public void ShouldNotAcceptInvalidUser() 
     { 
      // OPTION1 
      Mock<IMembershipService> membership = new Mock<IMembershipService>(); 
      //OPTION2 
      // Mock<AccountMembershipService> membership = new Mock<AccountMembershipService>(); 

      membership.Setup(m => m.ValidateUser(It.IsAny<string>(), It.IsAny<string>())) 
         .Returns(false); 
      var logonModel = new LoginModel() { EmailorUserName = "connorgerv", Password = "pasdsword1" }; 
      var controller = new AccountController(membership.Object); 

      // Act 
      var result = controller.Login(logonModel,"Index") as RedirectResult; 

      // Assert 
      Assert.That(result.Url, Is.EqualTo("Index")); 
      Assert.False(controller.ModelState.IsValid); 
      Assert.That(controller.ModelState[""], 
         Is.EqualTo("The user name or password provided is incorrect.")); 
     } 

     [Test] 
     public void ExampleForMockingAccountMembershipService() 
     { 
      var validUserName = "connorgerv"; 
      var validPassword = "passwordd1"; 
      var stubService = new Mock<CustomMembershipProvider>(); 
      bool val = false; 

      stubService.Setup(x => x.ValidateUser(validUserName, validPassword)).Returns(true); 

      Assert.IsTrue(stubService.Object.ValidateUser(validUserName, validPassword)); 
     } 

    } 



public class AccountController : Controller 
    { 
     public IMembershipService MembershipService { get; set; } 

     public AccountController(IMembershipService service){ 

      MembershipService=service; 
     } 

     protected override void Initialize(RequestContext requestContext) 
     { 
      if (MembershipService == null) { MembershipService = new AccountMembershipService(); } 

      base.Initialize(requestContext); 
     } 

     public ActionResult Index() 
     { 
      return RedirectToAction("Profile"); 
     } 


     public ActionResult Login() 
     { 
      if (User.Identity.IsAuthenticated) 
      { 
       //redirect to some other page 
       return RedirectToAction("Index", "Home"); 
      } 
      return View(); 
     } 

     // 
     // POST: /Account/Login 

     [HttpPost] 
     public ActionResult Login(LoginModel model, string ReturnUrl) 
     { 
      if (ModelState.IsValid) 
      { 
       if (MembershipService.ValidateUser(model.EmailorUserName, model.Password)) 
       { 

        SetupFormsAuthTicket(model.EmailorUserName, model.RememberMe); 

        if (Url.IsLocalUrl(ReturnUrl) && ReturnUrl.Length > 1 && ReturnUrl.StartsWith("/") 
         && !ReturnUrl.StartsWith("//") && !ReturnUrl.StartsWith("/\\")) 
        { 
         return Redirect(ReturnUrl); 
        } 
        return RedirectToAction("Index", "Home"); 
       } 
       ModelState.AddModelError("", "The user name or password provided is incorrect."); 
      } 

      // If we got this far, something failed, redisplay form 
      return View(model); 
     } 
    } 


    public class AccountMembershipService : IMembershipService 
    { 
     private readonly MembershipProvider _provider; 

     public AccountMembershipService() 
      : this(null) 
     { 
     } 

     public AccountMembershipService(MembershipProvider provider) 
     { 
      _provider = provider ?? Membership.Provider; 
     } 


     public virtual bool ValidateUser(string userName, string password) 
     { 
      if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName"); 
      if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password"); 

      return _provider.ValidateUser(userName, password); 
     } 

    } 
내가 MembershipService이 AccountController에서 Mock<IMembershipService> 것을 볼 수 있습니다 주석 옵션 1과 ShouldNotAcceptInvalidUser()을 실행하지만 결코에 MembershipService.ValidateUser에 단계 없을 때 어떻게됩니까

Membership in web.config of main application

<membership defaultProvider="CustomMembershipProvider"> 
    <providers> 
    <clear /> 
    <add name="CustomMembershipProvider" type="QUBBasketballMVC.Infrastructure.CustomMembershipProvider" connectionStringName="UsersContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" /> 
    </providers> 
</membership> 

public class CustomMembershipProvider : MembershipProvider 
{ 
    public override bool ValidateUser(string username, string password) 
    { 

     using (var usersContext = new UsersContext()) 
     { 
      var requiredUser = usersContext.GetUser(username, password); 
      var userApproved = usersContext.GetUserMem(username); 
      if (userApproved == null) return false; 
      return (requiredUser != null && userApproved.IsApproved != false); 
     } 
    } 
} 

로그인 액션.

내가 옵션 2 실행

는 MembershipService가 accountcontroller에서 Mock<AccountMembershipService>이며 차례로 세트에 System.Web.Security.SqlMembershipProvider

또한 ExampleForMockingAccountMembershipService() 아무튼 '이다 SqlMembershipProviderMembership.Provider으로는 null 매개 변수를 사용하여 AccountMembership Contstructor을 명중 제외하고 같은 일이 발생 주석 처리 t ValidateUser 메서드에서 모두 CustomMembershipProvider에있는 것처럼 보이며 항상 true를 반환합니다.

바라기를 이것은 내가 잘못 가고있는 곳을보기에 충분합니다. :/

+0

? (예 :'_provider'가 여전히 'SqlMembershipProvider'로 표시됩니까?) 테스트 프로젝트의 app.config에 구성을 추가 한 후입니까? – Lilshieste

+0

죄송합니다. 귀하의 회신을 본 적이 없으며 공급자가 여전히 SqlMembershipProvider로 표시됩니다! app.config에 설정을 추가하려고 시도했지만 운이 없었습니다! 이 코드가 작동해야합니까? '[테스트] public void ExampleForMockingAccountMembershipService() { var validUserName = "connorgerv"; var validPassword = "passwordd1"; var stubService = new Mock (); stubService.Setup (x => x.ValidateUser (validUserName, validPassword)). 반환 (true); Assert.IsTrue (stubService.Object.ValidateUser (validUserName, validPassword)); }' –

+0

어리석은 질문을하는 것이 아니라, * test * 프로젝트의'app.config' 설정을 변경 했습니까? (즉, 'AccountMembershipService'가 정의 된 프로젝트가 아니라 테스트가 정의 된 프로젝트입니다.) 코드가 작동해야한다면'CustomMembershipProvider'에 대한 코드를 보지 않고 말하기 어렵습니다. 즉,'CustomMembershipProvider'를 테스트하려고한다면 조롱하면 안됩니다. – Lilshieste

답변

0

코드를 제공해 주셔서 감사합니다. 나는 당신이 지금하고있는 일을 훨씬 잘 처리했다고 생각합니다.

ShouldNotAcceptInvalidUser 테스트의 경우 AccountMembershipService 대신 IMembershipService을 모의해야합니다 (옵션 2보다 옵션 1을 선택하십시오). 컨트롤러가 SUT이므로 움직이는 부품의 수를 최소화하기 위해 테스트에서 유일한 "실제"클래스 여야합니다.

옵션 1을 사용하면 MembershipService.ValidateUser이 코드로 들어가는 것을 기대할 이유가 없습니다. MembershipService은 모의 객체입니다. 그리고 그 메소드가 호출 될 때 항상 단지 false을 반환하도록 명시 적으로 말했습니다. 여기 코드를 기반으로 옵션 1을 사용하면이 테스트가 통과 될 것으로 기대됩니다.

다른 테스트에서는 ExampleForMockingAccountMembershipService, 당신은 이 아닌과 같은 SUT를 조롱하고 있습니다. SUT는 테스트에서 유일한 "실제"개체 여야합니다. 즉 개체를 조롱해야하며 SUT는 의미있는 작업을 수행하는 유일한 개체가되어야합니다. (테스트가 실패 할 경우 그 방법은, 당신은 때문에 SUT의 버그 있다는 확실히 알고있다.)

(주 : ValidateUser 항상 명시 적으로 당신이 SUT를 조롱 때문에 여기 true을 반환되었다가 항상 반환에 말했다 . 그것은 당신의 SUT를 조롱하는 것은 좋은 생각이 결코 이유 true이다 -. 조롱 당신이 테스트하려는 동작을 변경) 귀하가 제공 한 코드를 기반으로

, 당신이 CustomMembershipProvider을 조롱하는 이유입니다 같은데요 추상 기본 클래스 MembershipService을 완전히 구현하지 않기 때문입니다. 이것이 사실이라면 기본 구현을 제공하기 위해 조롱 프레임 워크에 의존하는 대신 누락 된 메소드를 수동으로 구현해야합니다. UsersContext : CustomMembershipProvider은 해당 종속성 중 하나를 인스턴스화 사실 여기 피려

[Test] 
    public void ExampleForMockingAccountMembershipService() 
    { 
     var validUserName = "connorgerv"; 
     var validPassword = "passwordd1"; 
     var sut = new CustomMembershipProvider(); 

     Assert.IsTrue(sut.ValidateUser(validUserName, validPassword)); 
    } 

뭔가 : 여기

난 당신처럼 보이도록이 테스트를하려는 이었다 믿는 것입니다. 단위 테스트에서는 CustomMembershipProvider이 SUT이므로 모든 종속성을 모방하고 싶을 것입니다. 이 경우 dependency injection을 사용하여이 종속성을 생성하는 객체 (예 : IUsersContextFactory)를 전달하고 테스트에서 모의 ​​팩토리 및 컨텍스트를 사용할 수 있습니다.

당신이 그 길을 가고 싶어하지 않으면, 당신의 테스트가 UsersContextCustomMembershipProvider또는 버그 버그로 인해 실패 할 수 있음에 유의하십시오.

따라서 테스트의 일반적인 논리는 확실합니다. 문제는 주로 테스트에서 모의 ​​객체의 역할에 대한 혼동으로 인해 발생합니다. 처음에는 얻을 수있는 어려운 개념의 종류,하지만 여기에 나를 도와 일부 자원 난이 배우는 때 어떻게 링크의 정보가 당신이 작동하지 않는 제공됩니다

"Dependency Injection in .Net" by Mark Seemann

"Test Doubles" by Martin Fowler

+0

이것은 크게 도움이되었습니다! 데이터베이스와 관련하여 또 다른 오류가 발생했습니다. 공급자가 열리지 않은 곳은 어디입니까? http://stackoverflow.com/questions/23288576/underlying-provider-failed-on-open –