Подсказки относительно того, как записать благоприятной для рефакторинга единице тесты TDD

Я работал над проектом MVC ASP.NET в течение приблизительно 8 месяцев теперь. По большей части я использовал TDD, некоторые аспекты были покрыты модульными тестами только после того, как я написал фактический код. Всего симпатичный проект имеет хорошее тестовое покрытие.

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

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

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

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

Править: Как Henning и tvanfosson, правильно отмеченный, это обычно - часть установки, которая является самой дорогой записать и поддержать. Поврежденные тесты являются (по моему опыту), обычно результатом рефакторинга к модели предметной области, которая не совместима с частью установки тех тестов.

13
задан csharpfolk 18 March 2017 в 13:51
поделиться

7 ответов

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

После того, как я долгое время следовал этим паттернам, я написал AutoFixture, которая представляет собой библиотеку с открытым исходным кодом, инкапсулирующую многие из этих паттернов ядра.

Она работает как Test Data Builder, но также может быть подключена к сети, чтобы работать как контейнер Auto-Mocking и делать много других странных и замечательных вещей.

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

Представьте, что у вас есть класс с этой конструкторной сигнатурой

public MyClass(Foo foo, Bar bar, Sgryt sgryt)

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

var sut = fixture.CreateAnonymous<MyClass>();

Основным преимуществом является то, что если вы решите рефакторизовать конструктор MyClass, то никакие тесты не прервутся, потому что AutoFixture разберется с этим за вас.

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

8
ответ дан 2 December 2019 в 00:31
поделиться

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

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

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

2
ответ дан 2 December 2019 в 00:31
поделиться

Эта статья мне очень помогла: http://msdn.microsoft.com/en-us/magazine/cc163665.aspx

С другой стороны, чудо нет Способ избежать рефакторинга тестов.

Все поставляется с ценой, и это особенно верно, если вы хотите сделать тестирование подразделения.

2
ответ дан 2 December 2019 в 00:31
поделиться

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

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

Однако это не очень хорошая вещь, потому что мы все еще должны создавать все эти значения в каждом тесте. Итак, мы сейчас изучаем наши тесты в более подробном стиле спецификации / BDD, что должно помочь уменьшить код установки, и поэтому количество времени, проведенного в поддержании тестов. Несколько ресурсов, которые вы можете проверить, это http://elegantcode.com/2009/12/22/specifications/ и стиль BDD тестирования с MSPEC http://elegantcode.com/2009 / 07/05 / MSPec-Take-2 /

1
ответ дан 2 December 2019 в 00:31
поделиться

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

Стоит отметить, что я попробую и держусь вдали от BDD / Context Spec, тем дальше от UI, который я получаю. Тестирование поведения отлично, но всегда ведет меня (возможно, я не делаю это правильно?) Для более крупных тестов Мессера, с большим количеством контекстных спецификаций, чем мне нравится.

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

0
ответ дан 2 December 2019 в 00:31
поделиться

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

1
ответ дан 2 December 2019 в 00:31
поделиться

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

вместо:

public class A {

   public void foo(B b) {
      String someField = b.getC().getD().getSomeField();
      // ...
   }
} 

измените его на:

public class A {

   public void foo(String someField) {
      // ...
   }
} 

Тогда настройка тестов станет тривиальной.

0
ответ дан 2 December 2019 в 00:31
поделиться
Другие вопросы по тегам:

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