2016-06-29 6 views
0

Я хотел бы знать, может ли кто-нибудь помочь мне с этим.Mock ApplicationUserManager для модульного тестирования Контроллеры MVC

Я пишу модульные тесты для конкретного контроллера. Этот контроллер наследует от BaseController и BaseController обладает этим свойством:

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

т е р для ApplicationUserManager является:

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:

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; 

Я попытался издеваться над этим, но поскольку это не виртуальная собственность (UserTokenProvider), это не позволяет мне, и я получаю это исключение:

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

Может ли кто-нибудь помочь мне с этой проблемой? Я просто хочу, чтобы дразнить это для того, чтобы проверить контроллер, который наследуется от BaseController, который имеет эту собственность ..

Благодаря

+1

Вместо насмешливого ApplicationUserManager, вы можете создать еще один конструктор для него и его экземпляра с помощью альтернативного конструктора? – bwyn

ответ

1

Спасибо за вашу помощь @bwyn

мне удалось взломать его с вашим предложение. Просто создал новый конструктор для ApplicationUserManager как это:

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); 

Спасибо вам всем!

+0

Я рад, что вы нашли решение, но если другой разработчик попытается использовать ApplicationUserManager, как остановить их от создания экземпляра с помощью вашего тестового конструктора (который, как я полагаю, бесполезен в реальной реализации)? –

+0

Здравствуйте, @mark_h, это хороший момент. Но когда я тестирую этот контроллер, я просто проверю функциональность и логику, я всегда буду считать, что пользователь будет всегда входить в систему, и мы получим действительный useriI из класса ApplicationUserManager.В реальном мире, потому что у меня есть 2 конструктора, я буду использовать правильный, где мы вводим IUserStore и IIdentityMessageService. Это ответили на ваш вопрос? Спасибо – legollas007

0

Как указано в одном из комментариев в вашем ответе, создание дополнительного конструктора может привести к тому, что другой разработчик использует неправильный.

Могу я предположить, что вместо этого вы попробуете следующее.

Переместите код внутри исходного конструктора ApplicationUserManager в новый защищенный виртуальный метод. Затем измените пустой конструктор, чтобы вызвать новый виртуальный метод.

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 когда модульное тестирование, который наследует ApplicationUserManager, переопределить унаследованное «CalledAfterConstruction» с только пустым методом, и вы в значительной степени есть вещи так, как вы делали в своем ответе.

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

    protected override void CalledAfterContruction() 
    { 

    } 
} 

Да это немного сложнее, но это не останавливает человек от неправильного использования исходного класса

+1

Вызов виртуальных методов в конструкторе является источником ошибок http://www.matthewedmondson.info/2012/08/virtual-method-call-in-contructor.html –