статические методы и юнит-тесты - PullRequest
6 голосов
/ 19 ноября 2010

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

Может ли кто-нибудь объяснить это несоответствие между лучшими практиками TDD и практической легкостью?

спасибо, A

Ответы [ 4 ]

14 голосов
/ 19 ноября 2010

Статический метод легко проверить, но то, что напрямую вызывает статический метод, обычно нелегко проверить независимо от статического метода, от которого он зависит. С помощью нестатического метода вы можете использовать экземпляр stub / mock / fake, чтобы упростить тестирование, но если код, который вы тестируете, вызывает статические методы, он фактически «привязан» к этому статическому методу.

3 голосов
/ 19 ноября 2010

Ответ на заданный вопрос, на мой взгляд, «объектно-ориентированный, кажется, все, о чем думают TDD».

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

Java-программисты, кажется, любят все усложнять, чтобы "сэкономить время позже".

Я советую применять некоторые гибкие принципы к вашему TDD: если это не вызывает проблемы, не решайте ее. Не переусердствуйте.

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

Если статические методы выполняются быстро, имитация не требуется.

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

Если вам нужно макетировать статический метод, помните, что есть способы сделать это вне OO-программирования.

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

2 голосов
/ 19 ноября 2010

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

Ссылка на статический метод не может быть смоделирована многими средами моделирования и не может быть переопределена.

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

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

0 голосов
/ 19 ноября 2010

Этот совет верен по большей части .. но не всегда.Мои комментарии не являются специфичными для C ++.

  1. написание тестов для статических методов (которые являются чистыми / не сохраняющими состояние функциями): то есть обработка входных данных для получения согласованного результата.например, Добавить ниже - всегда будет давать одно и то же значение, учитывая конкретный набор входов. нет проблем при написании тестов для них или кода, который вызывает такие чисто статические методы.
  2. написание тестов для статических методов, которые потребляют статическое состояние : например, GetAddCount ()ниже.Вызов его в нескольких тестах может привести к различным значениям.Следовательно, один тест может потенциально повредить выполнению другого теста - тесты должны быть независимыми.Поэтому теперь нам нужно ввести метод для сброса статического состояния, чтобы каждый тест мог начинаться с чистого листа (например, что-то вроде ResetCount ()).
  3. Написание тестов для кода, который обращается к статическим методам , но нет доступа исходного кода к зависимости: опять же зависит от свойств самих статических методов.Однако, если они грубые, у вас сложная зависимость.Если зависимость является объектом, то вы можете добавить установщик к зависимому типу и установить / внедрить поддельный объект для ваших тестов.Если зависимость статическая, вам может потребоваться значительный рефакторинг, прежде чем вы сможете надежно запустить тесты.(Например, добавьте объектную зависимость от среднего человека, которая делегирует статическому методу. Теперь подключите поддельного посредника для ваших тестов)

Давайте рассмотрим пример

public class MyStaticClass
{
  static int __count = 0;
  public static int GetAddCount()
  {  return ++__count;  }

  public static int Add(int operand1, int operand2)
  {  return operand1 + operand2; }

  // needed for testability
  internal static void ResetCount()
  {
     __count = 0;
  }
}

...

//test1
MyStaticClass.Add(2,3);        // => 5
MyStaticClass.GetAddCount();    // => 1

// test2
MyStaticClass.Add(2,3);  // => 5
//MyStaticClass.ResetCount(); // needed for tests
MyStaticClass.GetAddCount();  // => unless Reset is done, it can differ from 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...