Лучшие практики методов юнит-тестирования, которые содержат условные условия - PullRequest
1 голос
/ 19 декабря 2008

Я новичок в юнит-тестировании, и в настоящее время у меня проблема с поиском достойного способа тестирования методов, содержащих ветви.

Я создал небольшой демонстрационный метод, который, я надеюсь, можно использовать для объяснения проблемы.

public void ExportAccounts()
{
     int emptyAccounts = 0;
     int nonEmptyAccounts = 0;
     int errorous = 0;
     string outputPath = this.GetOutputPath();
     Account[] accounts = this.MyWebserviceAdapter.GetAccounts();
     foreach(Account account in accounts)
     {
        try 
        {
          if(account.Amount > 0)
          {
               this.ExportNonEmpty(outputPath, account);
               nonEmptyAccounts++;
          } else {
               this.ExportEmptyAccount(outputPath, account);
               emptyAccounts++;
          }
        } catch(Exception e) {
          logger.error(e);
          errorous++;
        }
     }
     logger.debug(string.Format("{0} empty / {1} non empty / {2} errorous", emptyAccounts, nonEmptyAccounts, errorous));
}

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

Также мои методы ExportNonEmpty () и ExportEmpty () являются частными, но записывают файлы в файловую систему. Должен ли я предоставить фиктивный FileProvider, чтобы файловая система не затрагивалась?

Должен ли я использовать ExportNonEmpty () и ExportEmpty (), чтобы иметь возможность проверить их отдельно? Эти методы также содержат несколько операторов if-then-else и могут генерировать исключения и еще много чего.

Я нахожу, если я создаю тест для каждого кодового пути, я копирую код из одного теста в другой - генерирую макеты и т. Д. Не правда ли, это немного странно?

Должен ли я выставить переменные счетчика как переменные out, чтобы иметь возможность проверить их после вызова метода?

this.GetOUtputPath () извлекает значения из файла конфигурации через ConfigurationManager, который является статическим. Должен ли я а) смоделировать это либо путем создания частичного макета для класса под тестом и перезаписать метод GetOutputPath, либо б) создать свой собственный ConfigurationAdapter, который можно макетировать?

Я использую Nunit и Rhino Mocks.

Ответы [ 2 ]

1 голос
/ 19 декабря 2008

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

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

Вы должны иметь возможность протестировать свои закрытые методы, добавив метод доступа для тестируемого класса. Один из них будет добавлен автоматически, если вы используете элемент меню «Создать юнит-тесты», находящийся в контекстном методе правой кнопкой мыши, или просто добавляете приватный метод как метку для создания юнит-теста при добавлении для всего класса. Для тестирования ExportAccounts просто используйте данные, которые, как вы знаете, будут вызывать и не будут генерировать исключения, чтобы можно было проверить как прямолинейную логику, так и обработку исключений.

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

Создайте ConfigurationAdapter (или Wrapper) и внедрите его в свой класс, чтобы удалить зависимость от статического класса. Макетируйте адаптер или предоставьте поддельную реализацию, на ваш выбор. Удаление зависимости - хороший пример для подражания. Я предпочитаю не издеваться и не заглушать что-либо в тестируемом классе.

РЕДАКТИРОВАТЬ: Для базового чтения по модульному тестированию я бы рекомендовал Прагматическое модульное тестирование (версия C #) и главу по модульному тестированию в Код завершен . Вы также можете выбрать Test Driven Development в .Net , но остальные более общие.

1 голос
/ 19 декабря 2008

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

Что касается проверки результата: выставление и тестирование счетчиков дало бы тест «белого ящика», где тест знает внутреннее состояние объекта, это дает более тщательный тест, но затрудняет его изменение реализация позже. (Если вы измените реализацию, тест может завершиться неудачей, даже если эффекты будут одинаковыми).

Обычно я предпочитаю проверять «черный ящик» и проверять только наблюдаемые извне последствия операции. Затем вы можете изменить внутреннюю структуру и регрессионный тест, если открытая функциональность остается прежней. Тем не менее, это может потребовать гораздо больше макетов.

Для java существует довольно много библиотек, которые могут помочь вам создавать фиктивные объекты, я не знаю, что такое .net, но я бы предположил, что то же самое имеет место.

...