Как выполнить тестирование закрытого кода без рефакторинга в отдельный класс? - PullRequest
5 голосов
/ 29 сентября 2010

Предположим, у меня есть частная процедура, которая выполняет некоторые вычисления:

private function TCar.Speed: float
{
   Result = m_furlogs * 23;
}

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

public function TCar.Speed: float
{
   Result = CalculateSpeed(m_furlogs);
}

private function TCar.CalculateSpeed(single furlogs): float 
{
   Result = furlogs * 23;
}

Теперь я могу выполнять все виды тестов на CalculateSpeed:

Check( CalculateSpeed(0)  =  0);
Check( CalculateSpeed(1)  = 23);
Check( CalculateSpeed(2)  = 46);
Check( CalculateSpeed(88) = -1);

За исключением того, что я не могу выполнить эти тесты, потому что CalculateSpeed является приватным для TCar.Абстрактной тенденцией модульного тестирования является то, что вы никогда не тестируете закрытый код - только общедоступные интерфейсы.На практике * x * Unit обычно не структурирован, чтобы иметь возможность доступа к закрытым методам отдельного тестируемого класса.

Проблема в том, что ни один из остальных классов не настроен для обработки юнит-тестов.Это самая первая процедура, которая будет проходить тестирование любого рода.И очень сложно настроить хост-класс набором начальных условий, которые позволят мне тестировать вызов CalculateSpeed с каждым набором входных данных, которые мне нужны.

Единственная альтернатива, которую я вижу, - это перемещениеэто частное вычисление в свой собственный TCarCalculateSpeed класс:

public class TCarCalculateSpeed
{  
   public function CalculateSpeed(float furlogs)
   {
      Result = furlogs * 23;
   }
}

Целый класс, посвященный раскрытию одного метода, который должен быть закрытым, просто чтобы я мог его проверить?

Класс взрыва.

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

Моя текущая, лучшая мысль - добавить Test метод к моему Carкласс, и просто назовите это:

TCar Car = new TCar();
Car.RunTests;

public procedure TCar.RunTests
{
   Check( CalculateSpeed(0)  =  0);
   Check( CalculateSpeed(1)  = 23);
   Check( CalculateSpeed(2)  = 46);
   Check( CalculateSpeed(88) = -1);
}

Но теперь я должен выяснить, как заставить TCar.RunTests быть запущенным внешним TestRunner, который предназначен только для использования TestCase классов.

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

Ответы [ 6 ]

3 голосов
/ 30 сентября 2010

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

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

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

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

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

3 голосов
/ 30 сентября 2010

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

1 голос
/ 30 сентября 2010

Если ваш язык поддерживает определения компилятора, вы можете использовать их в своих интересах.

(Пример кода в Delphi)

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

{$DEFINE UNIT_TESTS}

В коде класса проверьте условное определение и соответственно переключайтесь между открытым или защищенным и частным:

{$IFDEF UNIT_TESTS}
  public // or protected 
{$ELSE}
  private
{$ENDIF} 
    function CalculateSpeed: float;

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

1 голос
/ 30 сентября 2010

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

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

Например, в Java вы можете сделать закрытый метод package protected и поместите тестовый модуль в ту же упаковку.В C #, если я правильно помню, вы можете сделать его внутренним.В C ++ юнит-тест может быть другом.

1 голос
/ 30 сентября 2010

Может быть, вы могли бы создать тестовый класс, производный от тестируемого вами класса?

Вот пример из другого ТАК вопрос

1 голос
/ 29 сентября 2010

Можете ли вы создать несколько экземпляров класса TCar с разными начальными значениями m_furlogs? У вас есть где-нибудь на скорости? Вы можете проверить это, если это так.

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

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