Стоит ли тестировать частные методы или только публичные? - PullRequest
312 голосов
/ 19 сентября 2008

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

Ответы [ 30 ]

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

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

0 голосов
/ 15 февраля 2019

Речь идет не только о публичных или частных методах или функциях, но и о деталях реализации. Частные функции - это только один аспект деталей реализации.

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

A) Да, вы должны тестировать детали реализации:

Подумайте о функции сортировки, которая по соображениям производительности использует частную реализацию BubbleSort, если имеется до 10 элементов, и частную реализацию другого подхода сортировки (скажем, heapsort), если имеется более 10 элементов. Публичный API - это функция сортировки. Однако ваш набор тестов лучше использует знания о том, что на самом деле используются два алгоритма сортировки.

В этом примере, безусловно, вы можете выполнить тесты с открытым API. Это, однако, потребует наличия нескольких тестовых случаев, которые выполняют функцию сортировки с более чем 10 элементами, так что алгоритм heapsort достаточно хорошо протестирован. Наличие таких тестовых примеров само по себе указывает на то, что набор тестов связан с деталями реализации функции.

Если детали реализации функции сортировки изменятся, возможно, из-за того, что предел между двумя алгоритмами сортировки будет смещен, или что heapsort будет заменен слиянием или что-то еще: существующие тесты продолжат работать. Тем не менее, их ценность сомнительна, и их, вероятно, необходимо переработать, чтобы лучше протестировать измененную функцию сортировки. Другими словами, будут предприняты усилия по обслуживанию, несмотря на тот факт, что тесты проводились на общедоступном API.

B) Как проверить детали реализации

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

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

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

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

Тем не менее, это хорошее эмпирическое правило использовать «переднюю дверь первой» (см. http://xunitpatterns.com/Principles%20of%20Test%20Automation.html). Но имейте в виду, что она называется «передняя дверь первой», а не «только передняя дверь».

C) Резюме

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

0 голосов
/ 06 апреля 2019

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

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

public bool allPrime(int a, int b, int c)
{
  return andAll(isPrime(a), isPrime(b), isPrime(c))
}

private bool andAll(bool... boolArray)
{
  foreach (bool b in boolArray)
  {
    if(b == false) return false;
  }
  return true;
}

private bool isPrime(int x){
  //Implementation to go here. Sorry if you were expecting a prime sieve.
}

Теперь, если мы примем строгий подход к проверке только общедоступных функций, нам будет разрешено проверять только allPrime, а не isPrime или andAll.

Как тестер, нас могут интересовать пять вариантов для каждого аргумента: < 0, = 0, = 1, prime > 1, not prime > 1. Но чтобы быть тщательным, мы должны также увидеть, как каждая комбинация аргументов играет вместе. Так что это 5*5*5 = 125 тестовых случаев, нам необходимо тщательно протестировать эту функцию, согласно нашей интуиции.

С другой стороны, если бы нам было разрешено тестировать частные функции, мы могли бы охватить как можно больше с меньшим количеством тестовых случаев. Нам понадобится всего 5 тестовых случаев, чтобы проверить isPrime до того же уровня, что и наша предыдущая интуиция. И согласно гипотезе малого объема , предложенной Дэниелом Джексоном, нам нужно было только протестировать функцию andAll до небольшой длины, например. 3 или 4. Что будет не более 16 тестов. Итого 21 тест. Вместо 125. Конечно, мы, вероятно, хотели бы выполнить несколько тестов на allPrime, но мы бы не чувствовали себя настолько обязанными для исчерпывающего охвата всех 125 комбинаций входных сценариев, которые, как мы говорили, нам не безразличны. Всего несколько счастливых путей.

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

0 голосов
/ 24 сентября 2008

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

0 голосов
/ 02 ноября 2018

Я никогда не понимаю концепцию модульного тестирования, но теперь я знаю, какова его цель.

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

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

0 голосов
/ 23 марта 2017

Нет Вы не должны тестировать частные методы почему? и, более того, популярная среда для имитации, такая как Mockito, не обеспечивает поддержку тестирования частных методов.

0 голосов
/ 14 февраля 2017

Ответ на вопрос «Должен ли я проверить частные методы?» это "....... иногда". Обычно вы должны тестировать интерфейс ваших классов.

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

Вот пример:

class Thing
  def some_string
    one + two
  end

  private 

  def one
    'aaaa'
  end

  def two
    'bbbb'
  end

end


class RefactoredThing
def some_string
    one + one_a + two + two_b
  end

  private 

  def one
    'aa'
  end

  def one_a
    'aa'
  end

  def two
    'bb'
  end

  def two_b
    'bb'
  end
end

В RefactoredThing теперь у вас есть 5 тестов, 2 из которых вам пришлось обновить для рефакторинга, но функциональность вашего объекта действительно не изменилась. Итак, допустим, что все более сложно, и у вас есть метод, который определяет порядок вывода, такой как:

def some_string_positioner
  if some case
  elsif other case
  elsif other case
  elsif other case
  else one more case
  end
end

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

И, наконец, допустим, что ваш основной объект очень тяжелый, а метод довольно маленький, и вам действительно нужно убедиться, что вывод правильный. Вы думаете: «Я должен проверить этот частный метод!». Возможно, вы можете сделать свой объект легче, передавая некоторые тяжелые работы в качестве параметра инициализации? Тогда вы можете пропустить что-то более легкое и протестировать против этого.

0 голосов
/ 11 октября 2016

Один главный момент -

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

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

1010 * С другой стороны *

С другой стороны, главная проблема заключается в вызове частного метода вне исходного класса. Кроме того, существуют ограничения для насмешки частного метода в некоторых инструментах насмешки. (Пример: Мокито )

Хотя есть некоторые инструменты, такие как Power Mock , которые поддерживают это, это опасная операция. Причина в том, что для этого нужно взломать JVM.

Одно из возможных решений: (если вы хотите написать контрольные примеры для частных методов)

Объявите эти приватные методы как защищенные . Но это может быть не удобно для нескольких ситуаций.

0 голосов
/ 22 июля 2016

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

0 голосов
/ 25 мая 2012

Абсолютно ДА. В этом смысл юнит-тестирования, вы тестируете юниты. Частный метод - это Единица. Без тестирования частных методов TDD (Test Driven Development) было бы невозможно,

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