Модульный тест MVC4 и аутентификация Windows

Насколько я вижу, если мое приложение mvc4 не использует аутентификацию Windows (и поэтому мои контроллеры пытаются прочитать объекты пользователя), когда я создаю свой экземпляр контроллера из TestMethod, объект пользователя остается нулевым. Так что мои тесты проваливаются. Что я могу сделать, чтобы заставить их работать?

Дополнительная информация: Это мой тест:

[TestMethod]
public void Create()
{
   var ctrl = new LanguageController();
   var res = ctrl.Manage() as ViewResult;
   Assert.IsNotNull(res);
   Assert.AreEqual(res.ViewName, "Create");
}

И у моего LanguageController есть базовый класс:

public class LanguageController : MyController
{

У которого есть конструктор, внутри которого я пытаюсь открыть права пользователя с помощью внешнего диспетчера прав.

public class MyController : Controller
  {
     protected Rights rm;
     public MyController()
     {
        this.rm = RightManager.Discover(User.Identity);
     }

Здесь, в этом конструкторе, я вижу, что пользователь имеет значение null.


person Zoltan Hernyak    schedule 28.10.2013    source источник
comment
Не могли бы вы быть немного более конкретным? Например, что вы пытались до сих пор? Как выглядит ваш тестовый код и тестируемый код? Это поможет вам получить быстрый и точный ответ.   -  person Spock    schedule 28.10.2013
comment
Я добавил эту информацию к своему первоначальному вопросу.   -  person Zoltan Hernyak    schedule 29.10.2013


Ответы (1)


Хорошо, есть несколько проблем с вашим модульным тестом, и я рассмотрю их, когда объясню, почему пользователь имеет значение null.

Это просто потому, что вы не предоставили заглушенную версию экземпляра пользователя (IPrincipal). Поэтому вам нужно найти способ внедрить это в ваш контроллер. Важно, чтобы вы экстернализовали как можно больше зависимостей в вашем контроллере, чтобы он не предоставлял чистый контроллер для работы, но также и, что важно, продвигал тестируемость.

Что бы я сделал, введя зависимости, как показано ниже.

Ваша SUT (тестируемая система)

public class MyController : Controller
{
    protected Rights rm;
    public MyController(IPrincipal user, IRightManager rightManager)
    {
        this.rm = rightManager.Discover(user.Identity);
    }
}

public class LanguageController : MyController
{
    public LanguageController(IPrincipal user, IRightManager rightManager)
        : base(user, rightManager)
    { 
    }

    public ActionResult Manage()
    {
        return View("Manage");
    }
}

Это дает мне возможность внедрить поддельного пользователя, а также поддельного правого менеджера.

Так как же получить настоящего пользователя, RightManager, при запуске приложения во время выполнения?

Вы можете внедрить зависимости в контроллер во время создания контроллера.

Если вы не используете структуру внедрения зависимостей (в идеале следует), вы все равно можете внедрять зависимости ручным способом. Например, создание свойства в вашем контроллере и внедрение реального экземпляра в контроллер, а во время модульного тестирования внедрение поддельного экземпляра и т. д. Я не буду вдаваться в подробности, так как немного отклоняюсь, но вы можете найти много ТАК вопросы/веб-ссылки в отношении этого аспекта.

Ваш модульный тест Теперь у вас есть способ внедрить свои зависимости, которые вы можете легко внедрить из своего модульного теста. Вы можете либо использовать изоляционную структуру (также известную как структура объектов Mock), либо внедрить их как олдскульный способ - это написанные от руки макеты / подделки / заглушки. Я предлагаю использовать фреймворк Isolation. Создание подделок вручную приводит к ненужному дублированию кода и проблемам с обслуживанием. Поскольку я не знаю, какой фреймворк вы предпочитаете, я создал несколько рукописных подделок/моков/заглушек.

public class FakeRightManager : IRightManager {
    public Rights Discover(IIdentity identity) {
        return new Rights();
    }
}

public class MyFakeIdentity : IIdentity {
    public string AuthenticationType {
        get { throw new NotImplementedException(); }
    }

    public bool IsAuthenticated {
        get { throw new NotImplementedException(); }
    }

    public string Name {
        get { throw new NotImplementedException(); }
    }
}

public class MyFakePrincipal : IPrincipal {
    public IIdentity Identity {
        get { return new MyFakeIdentity(); }
    }

    public bool IsInRole(string role) {
        throw new NotImplementedException();
    }
}

Вы модульный тест:

    [TestMethod]
    public void ManageAction_Execute_ReturnsViewNameManager()
    {
        var fakeUser = new MyFakePrincipal();
        var fakeRightManager = new FakeRightManager();
        var ctrl = new LanguageController(fakeUser, fakeRightManager);

        var res = ctrl.Manage() as ViewResult;

        Assert.AreEqual<string>(res.ViewName, "Manage");
    } 

В своем тесте вы проверяете Assert.IsNotNull(res); в этом нет необходимости, так как если res равен нулю, ваше второе утверждение все равно не удастся.

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

person Spock    schedule 29.10.2013