Модульное тестирование входа в ASP.NET - PullRequest
7 голосов
/ 05 июня 2009

Я очень новичок в TDD и у меня проблемы с одним из моих модульных тестов. Я просто не могу понять, что делать дальше. :( Я пытаюсь выполнить юнит-тестирование службы под названием AccountService, и я тестирую метод с именем DoLogin (имя пользователя, пароль). Вот пример кода:

    [Test]
    public void User_With_Correct_Username_And_Pass_Should_Login_Successfully()
    {
        // Arrange
        var accountService = new AccountService();

        // Act
        bool result = accountService.DoLogin("test", "test");

        // Assert
        Assert.IsTrue(result);
    }

    public class AccountService : IAccountService
    {
      public bool DoLogin(string username, string password)
      {
        if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            return false;

        return true;
      }
    }

Итак, этот тест пройден, но что мне теперь делать ?! Как я могу проверить, действительный ли логин произошел? Нужно ли реализовывать интеграционный тест и проверять логин по реальной или в памяти БД? Извините, если я делаю вещи совершенно неправильно. Я действительно надеюсь, что однажды сломаю этот TDD. Спасибо

Ответы [ 3 ]

17 голосов
/ 05 июня 2009

Ваш опыт очень похож на мой. В то время как я продан на TDD и не поступил бы иначе, я, конечно, понимаю вашу путаницу. Важно помнить, что TDD - это философия дизайна. При этом, я думаю, я могу помочь устранить некоторые ваши разочарования.

  1. Начните с размышлений о том, чего вы пытаетесь достичь, не на уровне отдельного теста, а в том, что вы пытаетесь сделать. Если ваша задача (пользовательская история) включает в себя получение некоторых учетных данных и попытку аутентификации текущего пользователя на основе этих учетных данных, то начните с этого и продолжайте свой путь вниз. Вы, кажется, движетесь в этом направлении, только застревая на следующих шагах

  2. При работе над отдельным тестом думайте об этом с точки зрения ожидаемого поведения , а не просто проверяйте некоторые входы и выходы. Думайте о себе, как об использовании этого компонента, и просто напишите строку кода так, как вы хотите, чтобы она была написана. Пусть эта часть поможет управлять интерфейсом / контрактом вашего сервиса. Вы должны задать себе вопрос: «Если бы я назвал этот метод, как бы я узнал, что он работает? Что бы я ожидал от него?» Это определит, какие утверждения вам нужно сделать.

  3. Определите, каковы ваши внешние зависимости, и вместо этого используйте абстракции (принцип инверсии зависимости). Если эти зависимости являются чем-то, о чем вы заботитесь как часть проверки своего поведения, тогда используйте внедрение зависимостей , чтобы вы могли использовать mock в своем тесте.

  4. Всегда, всегда, всегда следуйте этому порядку [Напишите ваш тест, посмотрите, как он провалится, код для прохождения, рефакторинг]. ИЗУЧИТЕ У МОЕЙ ОШИБКИ !!! Поверь мне, это не подлежит обсуждению. В противном случае вы можете обвинить свои проблемы в TDD, если он не используется должным образом.

Хорошо, поэтому, собрав все это вместе с вашим примером и некоторыми тестовыми примерами от lance , мы могли бы сделать что-то вроде этого:

[Test]
public void ShouldAuthenticateValidUser()
{
    IMyMockDa mockDa = new MockDataAccess();
    var service = new AuthenticationService(mockDa);

    mockDa.AddUser("Name", "Password");

    Assert.IsTrue(service.DoLogin("Name", "Password"));

    //Ensure data access layer was used
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled);
}

[Test]
public void ShouldNotAuthenticateUserWithInvalidPassword()
{
    IMyMockDa mockDa = new MockDataAccess();
    var service = new AuthenticationService(mockDa);

    mockDa.AddUser("Name", "Password");

    Assert.IsFalse(service.DoLogin("Name", "BadPassword"));

    //Ensure data access layer was used
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled);
}

Хорошо, так что там много чего происходит, и, возможно, многое для исследования. Однако вы можете начать видеть, как можно провести тщательное тестирование, используя лучший дизайн. В вышеприведенных примерах важно отметить, что Mock Object настраивается, но вам не нужно проходить через всю эту боль. Там есть много насмешливых рамок. Например, используя RhinoMocks , ваш тест будет выглядеть так:

[Test]
public void ShouldAuthenticateValidUser()
{
    var mockRepo = new MockRepository();
    var mockDa = mockRepo.DynamicMock<IMyMockDa>();

    var service = new AuthenticationService(mockDa);

    using(mockRepo.Record())
    {
        //I realize this is a terrible method and should not exist if you
        // care about security, but for demonstration purposes...
        Expect.Call(mockDa.GetPassword("User")).Return("Password");
    }
    using(mockRepo.Playback())
    {
        Assert.IsTrue(service.DoLogin("User", "Password"));
    }
}

Привыкайте сначала делать вещи вручную, чтобы вы поняли концепции, а затем переходите к использованию фреймворка. Уф! Много информации, но, как видите, TDD - это целая философия дизайна. Однако это приведет к более чистому коду, лучшему дизайну и меньшему количеству ошибок.

1 голос
/ 05 июня 2009

Передайте то, что вы знаете как действительные и недействительные учетные данные, в DoLogin, а затем сравните результаты с ожидаемыми. Попробуйте представить все возможные (читай: разумные) комбинации / ввод параметров «имя пользователя» и «пароль», которые предоставит пользователь, и создайте тест для каждого из них.

Если верить вашей бизнес-логике DoLogin, мы определяем «действительное» имя пользователя (и «действительный» пароль) как все, что заполняется. Справедливости ради, ради обсуждения.

На ум приходят несколько простых тестов:

Login_With_Null_UserName_Fails()
Login_With_Populated_UserName_Succeeds()
Login_With_Empty_UserName_Fails()
Login_With_Null_Password_Fails()
Login_With_Populated_Password_Succeeds()
Login_With_Empty_Password_Fails()

Или рассмотрим комбинации:

Login_With_Null_UserName_And_Populated_Password_Fails()
Login_With_Populated_UserName_And_Populated_Password_Succeeds()
Login_With_Empty_UserName_And_Null_Password_Fails()
etc
etc
0 голосов
/ 05 июня 2009

У вас должен быть тест на то, что неверное имя пользователя или неверный пароль приводят к сбою DoLogin ().

Учитывая имя функции (DoLogin (), а не CheckLogin ()), я думаю, что функция также должна иметь некоторый побочный эффект. Тест должен проверить, что сторона влияет. Действительно нужно уточнить, что это такое, прежде чем кто-то сможет уточнить, как это следует проверять.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...