Тесты, которые в 2-3 раза больше тестируемого кода

AOL cyclops-react , в который я вношу свой вклад, также обеспечивает функцию zipping, как через реализацию расширенного потока , так и реализует интерфейс реактивных потоков ReactiveSeq и через StreamUtils, который предлагает многие из тех же функций с помощью статических методов для стандартных потоков Java.

 List> list =  ReactiveSeq.of(1,2,3,4,5,6)
                                                  .zip(Stream.of(100,200,300,400));


  List> list = StreamUtils.zip(Stream.of(1,2,3,4,5,6),
                                                  Stream.of(100,200,300,400));

Он также предлагает более обобщенную аппликативную основанную на zipping. Например.

   ReactiveSeq.of("a","b","c")
              .ap3(this::concat)
              .ap(of("1","2","3"))
              .ap(of(".","?","!"))
              .toList();

   //List("a1.","b2?","c3!");

   private String concat(String a, String b, String c){
    return a+b+c;
   }

И даже возможность соединять каждый элемент в одном потоке с каждым элементом в другом

   ReactiveSeq.of("a","b","c")
              .forEach2(str->Stream.of(str+"!","2"), a->b->a+"_"+b);

   //ReactiveSeq("a_a!","a_2","b_b!","b_2","c_c!","c2")

30
задан Egor Pavlikhin 6 April 2010 в 07:18
поделиться

13 ответов

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

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

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

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

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

16
ответ дан 28 November 2019 в 00:21
поделиться

Очень верный и хороший вопрос. Когда нужно, я следую простому принципу.

  1. Установите категорию для известных нам проблем (критические, высокие, низкие)
  2. Посмотрите, сколько времени у нас есть, и измените их, затем путем внутреннего обсуждения
  3. установите приоритеты
  4. Затем исправьте проблемы

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

1
ответ дан 28 November 2019 в 00:21
поделиться

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

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

2
ответ дан 28 November 2019 в 00:21
поделиться

Это чаще всего верно, чем нет. Ключ к выяснению того, хорошо это или плохо, - это выяснить причину, по которой тесты стали крупнее.

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

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

1
ответ дан 28 November 2019 в 00:21
поделиться

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

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

Об избегании тестов: если вы не тестируете определенные части своего кода, вы фактически подрываете всю концепцию и цель тестов, и тогда тесты фактически бесполезны.

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

0
ответ дан 28 November 2019 в 00:21
поделиться

Одна из вещей, которыми я руководствуюсь, когда пишу тесты или выполняю TDD (что, кстати, я узнал из ответа на один из моих вопросов по SO), заключается в том, что вам не нужно быть настолько осторожным с дизайном / архитектурой ваших тестов, насколько вы должны быть с вашим фактическим кодом. Тесты могут быть немного грязными и неоптимальными (с точки зрения разработки кода), если они правильно выполняют свою работу. Как и все советы по дизайну, его следует применять разумно, и ничто не заменит опыта.

0
ответ дан 28 November 2019 в 00:21
поделиться

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

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

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

-ОДНАКО-

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

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

0
ответ дан 28 November 2019 в 00:21
поделиться

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

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

6
ответ дан 28 November 2019 в 00:21
поделиться

Ну,

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

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

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

1
ответ дан 28 November 2019 в 00:21
поделиться

Тесты, которые в 2-3 раза больше, НЕ являются нормальными.

Используйте вспомогательные классы / методы в тестах.

Ограничьте объем тестов.

Эффективно используйте приспособление для тестирования.

Эффективно используйте тестовый разрыв.

Эффективное использование сред модульного тестирования.

И у вас больше не будет таких тестов.

0
ответ дан 28 November 2019 в 00:21
поделиться

Тестирование должно заключаться в нахождении правильный баланс, который зависит от множества различных факторов, таких как:

  • Бизнес-цель (подумайте «контроллер кардиостимулятора» против «менеджера по инвентаризации фильмов»)
  • Навыки разработчиков.
  • текучесть кадров (как часто люди добавляются к пул разработчиков)
  • Сложность (программного обеспечения, связанного с «бизнес-целью» выше)

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

1
ответ дан 28 November 2019 в 00:21
поделиться
  • Если вы тестируете простые (CRUD) операции, вполне логично иметь более длинные тесты
  • В противном случае я полагаю, вы можете реорганизовать свой код, чтобы повторяющийся код перемещался в отдельные методы
  • Если вы используете Java, вы можете использовать checkstyle (или другие инструменты) для проверки дублирования кода
1
ответ дан 28 November 2019 в 00:21
поделиться

Да, это нормально. Не проблема, что ваш тестовый код длиннее, чем ваш производственный код.

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

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

См. Также Соотношение тестового кода SQLite и производственного кода

0
ответ дан 28 November 2019 в 00:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: