Модульное тестирование пользовательского MembershipProvider.ValidateUser с использованием кода в Global.asax - PullRequest
2 голосов
/ 01 февраля 2012

У меня есть модульный тест для проверки моего метода AccountController.LogIn.Результат перенаправления возвращается, чтобы указать на успех, в противном случае возвращается viewresult.

Тест всегда завершается неудачей, поскольку тип возвращаемого значения всегда viewresult, даже если тест должен возвращать успех, поскольку учетные данные действительны, однако я не могу 'не определить, где проблема.Мой TestMethod: CustomerRepositoryTest.cs

[TestMethod]
public void Can_Login_With_Valid_Credentials()
{
     //  Arrange
     Mock<IAddressRepository> mockAddressRepository = new Mock<IAddressRepository>();
     Mock<ICustomerRepository> mockCustomerRepository = new Mock<ICustomerRepository>();
     Mock<IOrderRepository> mockOrderRepository = new Mock<IOrderRepository>();

     LoginViewModel model = new LoginViewModel
     {
         Email = "me@5.com",
         Password = "password"
     };

     AccountController target = new AccountController(mockCustomerRepository.Object, mockAddressRepository.Object, mockOrderRepository.Object);

   //  Act
    ActionResult result = target.LogIn(model);

    //  Assert
    Assert.IsInstanceOfType(result, typeof(RedirectResult));
    Assert.AreEqual("", ((RedirectResult)result).Url);
    }

Когда я запускаю тест, при входе в ValidateUser AccountController.cs

происходит сбой в методе входа в My AccountController.
if (Membership.ValidateUser(LoginModel.Email, LoginModel.Password))
{
  ...
 return RedirectToRoute(new
 {
    controller = "Account",
    action = "Details"
 });
}
else
{
   return View();
}

Мой пользовательский MembershipProvider ValidateUser выглядит следующим образом:

AccountMembershipProvider.cs

public class AccountMembershipProvider : MembershipProvider
{
     [Inject]
    public ICustomerRepository repository { get; set; }

    public override bool ValidateUser(string username, string password)
    {
       var cust = repository.GetAllCustomers().SingleOrDefault..

Когда я обычно запускаю приложение, т.е. не тестирую, логинработает отлично.В приложении я внедряю CustomerRepository в пользовательский поставщик членства в Global.asax :

    public class MvcApplication : System.Web.HttpApplication
    {
      private IKernel _kernel = new StandardKernel(new MyNinjectModules());

      internal class MyNinjectModules : NinjectModule
      {
        public override void Load()
        {
            Bind<ICustomerRepository>().To<CustomerRepository>();
        }
      }

      protected void Application_Start()

  {
   _kernel.Inject(Membership.Provider);
   ...

. Является ли это случаем, что код Global.asax не запускается во время модульного тестирования?и поэтому мой пользовательский провайдер не вводится, следовательно, произошел сбой?

UPDATE Я высмеял свой класс Provider и передал ему поддельный объект CustomerRepository.

Mock<AccountMembershipProvider> provider = new Mock<AccountMembershipProvider>();

provider.Object.repository = mockCustomerRepository.Object;

Затем я создал настройку для метода, который я пытаюсь протестировать:

 mockCustomerRepository.Setup(m => m.IsValidLogin("me@5.com", "password")).Returns(true);

Но, к сожалению, я все еще получаю ошибку каждый раз.Чтобы ответить на вопрос о том, нужен ли мне настоящий или смоделированный объект для теста - я не привереда, я просто хочу, чтобы он работал в данный момент!

ОБНОВЛЕНИЕ 2

Я внес эти изменения, и, хотя они все еще не работают, это позволило мне определить конкретную проблему.Во время отладки теста я обнаружил, что при вызове переопределенного

Membership.ValidateUser(LoginModel.Email, LoginModel.Password)

Membership.Provider имеет тип SqlMembershipProvider (который предположительно является типом по умолчанию), и, следовательно, проверка завершается неудачей.

ЕслиЯ приведу провайдера к своему провайдеру ...

((AccountMembershipProvider)Membership.Provider).ValidateUser(LoginModel.Email, LoginModel.Password)

Я получаю исключение InvalidCastException при запуске теста.Таким образом, похоже, что мой поддельный AccountMembershipProvider не используется для теста, а вместо этого используется поставщик по умолчанию.

Я думаю, вы уже определили это в комментарии:

// set your mock provider in your AccountController

Однако я не уверен, что именно вы имеете в виду - у меня в свой AccountController нет свойства для назначения провайдера, и я не вставляю его в конструктор.

Ответы [ 2 ]

3 голосов
/ 01 февраля 2012

Ваш первоначальный вопрос: "Это тот случай, когда код Global.asax не запускается во время модульного тестирования? И поэтому мой пользовательский поставщик не вводится, следовательноошибка? "

Мой ответ:

Да.

Файл global.asax используется ASP.Netи МКС во время выполнения.Он компилируется, когда сервер получает свой первый запрос.

Когда вы тестируете, вы находитесь не в контексте веб-приложения ASP.Net, работающего в ISS, а скорее в программе, запущенной в тестовом сеансе.Это означает, что ваш global.asax не будет вызван.

Что еще более важно, когда вы звоните:

Mock<ICustomerRepository> mockCustomerRepository = new Mock<ICustomerRepository>();

Ninject не будет вызываться для заполнения импорта.Moq создаст макет на основе интерфейса.Никакой реальный объект не будет создан.

Поскольку вы не определили какие-либо методы установки, а именно:

mockCustomerRepository.Setup(mock => mock.MyAuthenticateMethod()).Returns(true);

Вы передаете макет без определенного поведения. По умолчанию они возвращают false.Это, вероятно, объясняет, почему вы всегда получаете результат просмотра.

Что вам нужно сделать, это определить методы настройки для методов, которые вам нужно смоделировать.

Это методы CustomerRepository, которые будут вызывать вас при вызове:

target.LogIn(model);

Также обратите внимание, что ваш AccountMembershipProvider не получит свою инъекцию CustomerRepository, поскольку NInject не будетиспользуемый.Если вы тестируете AccountController и он не является статическим (Moq не работает со статическим), вам следует подумать о том, чтобы издеваться над AccountMembershipProvider.Если вы не можете, то вам нужно будет предоставить ваш смоделированный экземпляр CustomerRepository для AccountMembershipProvider.repository в ваших тестах.

Другое решение, вместо создания Moq-макета, вы также можете создать вручную (с новым) реальный экземпляр CustomerRepository в вашем тесте.

Вы могли бы сделать это Ninject, но на этом этапе почему?Вы можете создать его самостоятельно, и вы знаете, какой тип создавать.

Все сводится к тому, нужен ли вам для этого теста макет или реальный экземпляр объекта.

Обновление:

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

Что вам нужно сделать, это примерно так:

Mock<AccountMembershipProvider> provider = new Mock<AccountMembershipProvider>();
// set your mock provider in your AccountController

provider.Setup(m => m.ValidateUser("me@5.com", "password")).Returns(true);

Обновление 2:

Я думаю, вы довольно близки к проведению тестаРабота.Не видя весь ваш код (тестируемый и тестируемый класс), я больше не могу вам помочь.Мне также кажется, что я ответил на ваш первоначальный вопрос, но если вы все еще застряли, вы можете получить дополнительную помощь, задав новый вопрос, касающийся проблемы, которую вы сейчас решаете.

1 голос
/ 01 февраля 2012

В вашем коде вы только создаете контроллер, но не запускаете инициализацию для членства.Я рекомендую вам создать свой собственный UserService с методом ValidateUser и другим, который вам нужен вместо использования членства в статическом классе.

...