Модульное тестирование пустых методов? - PullRequest
145 голосов
/ 29 октября 2008

Каков наилучший способ модульного тестирования метода, который ничего не возвращает? В частности, в C #.

Что я действительно пытаюсь проверить, так это метод, который берет файл журнала и анализирует его на предмет определенных строк. Строки затем вставляются в базу данных. Ничего из того, что не было сделано раньше, но, будучи ОЧЕНЬ новичком в TDD, мне интересно, возможно ли это проверить или это то, что на самом деле не тестировали.

Ответы [ 11 ]

135 голосов
/ 29 октября 2008

Если метод ничего не возвращает, это либо одно из следующих значений

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

Обязательные методы - вы можете проверить, действительно ли задание было выполнено. Проверьте, действительно ли произошло изменение состояния. например,

void DeductFromBalance( dAmount ) 

можно проверить, проверив, действительно ли баланс после отправки этого сообщения меньше первоначального значения по dAmount

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

void OnAccountDebit( dAmount )  // emails account holder with info

можно проверить, проверив, отправляется ли электронное письмо

Опубликуйте более подробную информацию о вашем фактическом методе, и люди смогут ответить лучше.
Обновление : Ваш метод делает 2 вещи. Я бы на самом деле разделил его на два метода, которые теперь можно независимо протестировать.

string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );

String [] можно легко проверить, предоставив первому методу фиктивный файл и ожидаемые строки. Второй вариант немного сложен. Вы можете использовать Mock (google или search stackflowflow на платформах mocking), чтобы имитировать БД, или поразить реальную БД и убедиться, что строки были вставлены в нужное место. Проверьте эту ветку на наличие хороших книг ... Я бы порекомендовал прагматическое модульное тестирование, если вы в затруднении.
В коде это будет использоваться как

InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
55 голосов
/ 29 октября 2008

Проверьте его побочные эффекты. Это включает в себя:

  • Выдает ли оно какие-либо исключения? (Если это так, проверьте, что это так. Если это не так, попробуйте некоторые угловые случаи, которые могут, если вы не будете осторожны, - нулевые аргументы - самая очевидная вещь.)
  • Хорошо ли играет со своими параметрами? (Если они изменчивы, мутирует ли он, когда не должен, и наоборот?)
  • Правильно ли это влияет на состояние объекта / типа, к которому вы его вызываете?

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

27 голосов
/ 29 октября 2008

Как всегда: проверьте, что метод должен делать!

Должно ли оно где-нибудь изменить глобальное состояние (запах кода!)?

Должен ли он вызывать интерфейс?

Должно ли оно вызывать исключение при вызове с неверными параметрами?

Должно ли оно вызывать исключения при вызове с правильными параметрами?

Должно ли это ...?

9 голосов
/ 30 мая 2014

Void возвращают типы / Подпрограммы - старые новости. Я не делал возврат типа Void (если я не был очень ленивым) в течение примерно 8 лет (со времени этого ответа, так что немного раньше, чем этот вопрос был задан).

Вместо метода, подобного:

public void SendEmailToCustomer()

Создайте метод, который следует парадигме Microsoft int.TryParse ():

public bool TrySendEmailToCustomer()

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

Кроме того, bool - не единственный тип состояния. Существует множество случаев, когда ранее созданная подпрограмма могла фактически возвращать три или более различных состояния (хорошее, нормальное, плохое и т. Д.). В этих случаях вы просто используете

public StateEnum TrySendEmailToCustomer()

Однако, хотя парадигма Try несколько отвечает на этот вопрос о том, как проверить пустоту, есть и другие соображения. Например, во время / после цикла «TDD» вы выполняете «Рефакторинг» и замечаете, что вы делаете две вещи с помощью вашего метода ... тем самым нарушая «Принцип единой ответственности». Так что об этом нужно позаботиться в первую очередь. Во-вторых, вы могли определить зависимость ... вы касаетесь "постоянных" данных.

Если вы выполняете работу с данными в рассматриваемом методе, вам необходимо выполнить рефакторинг в n-уровневую или n-слойную архитектуру. Но мы можем предположить, что когда вы говорите «Строки затем вставляются в базу данных», вы фактически имеете в виду, что вызываете уровень бизнес-логики или что-то в этом роде. Да, мы это предположим.

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

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)

Теперь, когда вы можете принять интерфейс вашего объекта уровня бизнес / данных, вы можете смоделировать его во время модульных тестов и не иметь никаких зависимостей или боязни "случайного" интеграционного тестирования.

Итак, в вашем живом коде вы передаете объект REAL IBusinessDataEtc. Но в вашем модульном тестировании вы передаете объект MOCK IBusinessDataEtc. В этом макете вы можете включить неинтерфейсные свойства, такие как int XMethodWasCalledCount или что-то, чьи состояния обновляются при вызове методов интерфейса.

Таким образом, ваш модульный тест пройдет через ваш метод (ы) в вопросе, выполнит любую логику и вызовет один или два, или выбранный набор методов в вашем IBusinessDataEtc объекте. Когда вы делаете свои утверждения в конце модульного теста, у вас есть пара вещей, которые нужно проверить сейчас.

  1. Состояние подпрограммы, которая теперь является методом Try-Paradigm.
  2. Состояние вашего ложного IBusinessDataEtc объекта.

Для получения дополнительной информации об идеях внедрения зависимостей на уровне конструкции ... как они относятся к модульному тестированию ... посмотрите шаблоны проектирования Builder. Он добавляет еще один интерфейс и класс для каждого текущего интерфейса / класса, который у вас есть, но они очень малы и обеспечивают ОГРОМНОЕ увеличение функциональности для лучшего модульного тестирования.

5 голосов
/ 29 октября 2008

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

4 голосов
/ 12 мая 2016

Попробуйте это:

[TestMethod]
public void TestSomething()
{
    try
    {
        YourMethodCall();
        Assert.IsTrue(true);
    }
    catch {
        Assert.IsTrue(false);
    }
}
4 голосов
/ 29 октября 2008

Предположительно, метод что-то делает, а не просто возвращает?

Если это так, тогда:

  1. Если он изменяет состояние объекта-владельца, вам следует проверить, что состояние изменилось правильно.
  2. Если он принимает какой-либо объект в качестве параметра и модифицирует этот объект, то следует проверить, что объект правильно изменен.
  3. Если в некоторых случаях выдается исключение, проверьте, правильно ли выбрасываются эти исключения.
  4. Если его поведение варьируется в зависимости от состояния его собственного объекта или какого-либо другого объекта, задайте состояние и проверьте правильность метода у одного из трех описанных выше методов тестирования).

Если вы дадите нам знать, что делает метод, я мог бы быть более конкретным.

3 голосов
/ 29 октября 2008

Используйте Rhino Mocks , чтобы установить, какие вызовы, действия и исключения могут ожидаться. Предполагая, что вы можете издеваться или заглушить части вашего метода. Трудно понять, не зная здесь некоторых подробностей о методе или даже контексте.

2 голосов
/ 29 октября 2008

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

0 голосов
/ 29 мая 2019

Вы даже можете попробовать это так:

[TestMethod]
public void ReadFiles()
{
    try
    {
        Read();
        return; // indicates success
    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...