Должно ли это быть "Arrange-Assert-Act-Assert"? - PullRequest
89 голосов
/ 20 июня 2009

Что касается классического тестового шаблона Arrange-Act-Assert , я часто добавляю встречное утверждение, предшествующее Act. Таким образом, я знаю, что проходное утверждение действительно является результатом действия.

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

Ваши тесты следуют этой схеме? Почему или почему нет?

Обновление Разъяснение: первоначальное утверждение по существу противоположно окончательному утверждению. Это не утверждение, что Arrange работал; это утверждение, что закон еще не сработал.

Ответы [ 14 ]

116 голосов
/ 20 июня 2009

Это не самая распространенная вещь, но все же достаточно распространенная, чтобы иметь собственное имя. Эта техника называется Guard Assertion . Вы можете найти подробное описание этого на странице 490 в превосходной книге xUnit Test Patterns Жерара Месароша (настоятельно рекомендуется).

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

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

29 голосов
/ 19 августа 2010

Также может быть указано как Arrange- Предположим, -Act-Assert.

В NUnit есть технический дескриптор для этого, как в следующем примере: http://nunit.org/index.php?p=theory&r=2.5.7

8 голосов
/ 23 июня 2009

Вот пример.

public void testEncompass() throws Exception {
    Range range = new Range(0, 5);
    assertFalse(range.includes(7));
    range.encompass(7);
    assertTrue(range.includes(7));
}

Возможно, я написал Range.includes(), чтобы просто вернуть true. Я не сделал, но я могу представить, что я мог бы иметь. Или я мог бы написать это неправильно любым другим способом. Я хотел бы надеяться и ожидать, что с TDD я действительно понял это правильно - это includes() просто работает - но возможно я не сделал. Таким образом, первое утверждение является проверкой работоспособности, чтобы убедиться, что второе утверждение действительно имеет смысл.

Прочтите само по себе, assertTrue(range.includes(7)); говорит: «утверждайте, что измененный диапазон включает 7». Прочитайте в контексте первого утверждения: «Утвердите, что , вызывая encompass () , заставляет его включать 7. И поскольку encompass - это тестируемый нами модуль, я думаю, что он какой-то (маленький) значение.

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

7 голосов
/ 28 февраля 2014

Тест Arrange-Assert-Act-Assert всегда можно реорганизовать в два теста:

1. Arrange-Assert

и

2. Arrange-Act-Assert

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

Это дает преимущество в том, что дает более точную обратную связь о том, провалилась ли фаза Arrange или Act, в то время как в оригинальном Arrange-Assert-Act-Assert они совпадают, и вам придется копать глубже и исследовать, что именно провалилось и почему потерпел неудачу, чтобы узнать, потерпел ли неудачу Соглашение или Закон.

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

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

1 голос
/ 01 ноября 2013

Взгляните на статью Википедии о Дизайн по контракту . Arrange-Act-Assert святая троица - это попытка закодировать некоторые из тех же понятий, и она посвящена доказательству правильности программы. Из статьи:

The notion of a contract extends down to the method/procedure level; the
contract for each method will normally contain the following pieces of
information:

    Acceptable and unacceptable input values or types, and their meanings
    Return values or types, and their meanings
    Error and exception condition values or types that can occur, and their meanings
    Side effects
    Preconditions
    Postconditions
    Invariants
    (more rarely) Performance guarantees, e.g. for time or space used

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

1 голос
/ 21 сентября 2011

Я сейчас делаю это. A-A-A-A другого типа

Arrange - setup
Act - what is being tested
Assemble - what is optionally needed to perform the assert
Assert - the actual assertions

Пример теста обновления:

Arrange: 
    New object as NewObject
    Set properties of NewObject
    Save the NewObject
    Read the object as ReadObject

Act: 
    Change the ReadObject
    Save the ReadObject

Assemble: 
    Read the object as ReadUpdated

Assert: 
    Compare ReadUpdated with ReadObject properties

Причина в том, что ACT не содержит чтения ReadUpdated, потому что он не является частью действия. Акт только меняется и сохраняется. Так что на самом деле, ARRANGE ReadUpdated для подтверждения, я вызываю ASSEMBLE для подтверждения. Это сделано для предотвращения путаницы в разделе ARRANGE

ASSERT должен содержать только утверждения. Это оставляет ASSEMBLE между ACT и ASSERT, который устанавливает assert.

И наконец, если вы потерпели неудачу в Arrange, ваши тесты неверны, потому что у вас должны быть другие тесты, чтобы предотвратить / найти эти тривиальные ошибки. Поскольку для сценария, который я представляю, уже должны быть другие тесты, которые проверяют READ и CREATE. Если вы создаете «Защитное утверждение», возможно, вы нарушаете DRY и создаете обслуживание.

1 голос
/ 04 августа 2011

В общем, мне очень нравится "Arrange, Act, Assert" и использую его как свой личный стандарт. Однако единственное, что не напоминает мне сделать, - это расстроить то, что я организовал, когда утверждения сделаны. В большинстве случаев это не вызывает большого раздражения, так как большинство вещей автоматически исчезают через сборку мусора и т. Д. Однако, если вы установили соединения с внешними ресурсами, вы, вероятно, захотите закрыть эти соединения, когда закончите. с вашими утверждениями, или у вас есть сервер или дорогой ресурс, где-то где-то есть связи или жизненно важные ресурсы, которые он может отдать кому-то другому. Это особенно важно, если вы один из тех разработчиков, которые не используют TearDown или TestFixtureTearDown для очистки после одного или нескольких тестов. Конечно, «Arrange, Act, Assert» не несет ответственности за мою неспособность закрыть то, что я открываю; Я упоминаю только об этом "gotcha", потому что я еще не нашел хороший синоним "A-word" для "dispose", чтобы рекомендовать! Есть предложения?

1 голос
/ 05 августа 2010

Я делал это раньше, когда исследовал провал теста.

После значительных царапин на голове я обнаружил, что причина в том, что методы, вызванные во время "Arrange", не работали правильно. Провал теста вводил в заблуждение. Я добавил Assert после аранжировки. Это привело к провалу теста в месте, которое высветило актуальную проблему.

Я думаю, что здесь есть и запах кода, если часть теста Arrange слишком длинная и сложная.

1 голос
/ 20 июня 2009

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

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

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

1 голос
/ 20 июня 2009

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

...