2016-06-29 7 views
0

누군가가이 문제를 해결할 수 있는지 알고 싶습니다.단위 테스트 용 MVC 컨트롤러 모의 ApplicationUserManager

특정 컨트롤러에 대한 단위 테스트를 작성 중입니다.

var store = new Mock<IUserStore<ApplicationUser>>(); 
var emailService = new Mock<IIdentityMessageService>(); 
var applicationUserManager = new Mock<ApplicationUserManager>(store.Object, emailService.Object); 
this.targetController.UserManager = applicationUserManager.Object; 
var dataprotectionprovided = new Mock<IDataProtectionProvider>(); 
applicationUserManager.Setup(r => r.UserTokenProvider).Returns(new DataProtectorTokenProvider<ApplicationUser, string>(dataprotectionprovided.Object.Create("ASP.NET Identity"))); 
this.targetController.UserManager = applicationUserManager.Object; 
:

public ApplicationUserManager(IUserStore<ApplicationUser> store, IIdentityMessageService emailService) 
     : base(store) 
    { 
     this.EmailService = emailService; 

     var dataProtectionProvider = Startup.DataProtectionProvider; 
     this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity")); 
    } 

이 내가 ApplicatonUserManager 클래스를 조롱하고있는 무슨이다 : 그것은 컨트롤러는 BaseController에서 상속 및 BaseController이 속성이 있는지 :

private ApplicationUserManager userManager; 
public ApplicationUserManager UserManager 
{ 
    get { return this.userManager ?? this.Request.GetOwinContext().GetUserManager<ApplicationUserManager>(); } 
    set { this.userManager = value; } 
} 

ApplicationUserManager의 ctor에은을

나는 이것을 모의하려고했지만 이것이 가상 속성 (UserTokenProvider)이 아니기 때문에 나를 허락하지 않고이 예외가 발생합니다 :

System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: r => r.UserTokenProvider 

누구든지이 문제를 해결할 수 있습니까? 난 그냥 그것을 균열 관리해야

@bwyn 도와

+1

보다는 조롱하는 사람들을 중지합니까? – bwyn

답변

1

감사합니다 .. 해당 속성이있는 BaseController에서 상속 컨트롤러를 테스트하기 위해이 조롱

감사하려는 암시. 다음

public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store) 
    { 
    } 

그리고 단위 테스트 :

var user = new ApplicationUser { User = new User { UserId = 1 } }; 

     var store = new Mock<IUserStore<ApplicationUser>>(MockBehavior.Strict); 
     store.As<IUserStore<ApplicationUser>>().Setup(x => x.FindByIdAsync(It.IsAny<string>())).ReturnsAsync(user); 
     this.targetController.UserManager = new ApplicationUserManager(store.Object); 

이 여러분 모두 감사합니다 그냥 새로운이 같은 ApplicationUserManager에 대한 생성자를 만들어!

+0

솔루션을 찾게되어 기쁩니다. 다른 개발자가 ApplicationUserManager를 사용하려고 시도하면 어떻게 테스트 생성자를 사용하여 인스턴스를 만들지 못하게됩니까? (실제 구현에서는 사용하지 않는다고 가정) –

+0

안녕하세요 @mark_h 좋은 지적입니다. 하지만이 컨트롤러를 테스트 할 때 기능 및 논리를 테스트하기 위해 항상 사용자가 항상 로그인되어 있다고 가정하고 ApplicationUserManager 클래스에서 유효한 useriI를 가져옵니다.현실 세계에서는 2 개의 생성자가 있기 때문에 IUserStore 와 IIdentityMessageService를 삽입 한 올바른 생성자를 사용합니다. 이 질문에 답변을 했습니까? 감사합니다 – legollas007

0

답변에있는 주석 중 하나에서 지적한 것처럼 추가 생성자를 만들면 다른 개발자가 잘못된 생성자를 사용하게 될 수 있습니다.

대신 다음을 시도해 볼 것을 제안 할 수 있습니까?

원본 ApplicationUserManager 생성자의 코드를 새 보호 가상 메서드로 이동하십시오. 그런 다음 빈 생성자를 수정하여 새 가상 메서드를 호출합니다. ApplicationUserManager을 상속 단위 테스트, 그냥 빈 방법으로 상속 된 'CalledAfterConstruction'을 무시하고 당신은 꽤 많은 것들을 당신이 대답했던 방법이 때

public class ApplicationUserManager 
{ 
    public ApplicationUserManager(IUserStore<ApplicationUser> store, IIdentityMessageService emailService) 
: base(store) 
    { 
     CalledAfterConstruction(); 
    } 

    protected virtual void CalledAfterConstruction() 
    { 
     this.EmailService = emailService; 

     var dataProtectionProvider = Startup.DataProtectionProvider; 
     this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity")); 
    } 
} 

지금 새로운 MockApplicationUserManager 클래스를 만들 수 있습니다.

public class MockClass : ApplicationUserManager 
{ 
    public MockClass(IUserStore<ApplicationUser> store, IIdentityMessageService emailService) : base(store, emailService) 
    { 
    } 

    protected override void CalledAfterContruction() 
    { 

    } 
} 

예이 조금 더 복잡하지만 당신이 그것을 또 다른 생성자를 생성하고 다른 생성자를 통해 인스턴스화 할 수있는 ApplicationUserManager를 원래 클래스 오용

+1

생성자에서 가상 메서드를 호출하면 오류의 원인이됩니다 http://www.matthewedmondson.info/2012/08/virtual-method-call-in-contructor.html –