Agile: сценарий ATDD для модели

Я новичок в TDD и ATDD и пытаюсь понять связь между пользовательской историей и ее критериями приемлемости. Для контекста я создаю трехуровневое приложение на C# с внешним интерфейсом MVC.

Скажем, например, что у меня есть следующая пользовательская история:

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

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

Например, может быть, у него есть свойство «Количество машин», которое должно быть больше нуля.

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

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

Я полагаю, что мог бы проверить правило № 2, проверив, что недопустимое состояние модели в контроллере перенаправляет, например, на ту же страницу - и есть МНОЖЕСТВО примеров этого.

Однако разве для этого не требуется украшать модель представления — и что в конечном итоге это реализует бизнес-правило с точки зрения пользователя? (таким образом удовлетворяя #1?)

Скажем, у меня есть следующий вид оператора/модуля-теста:

[Test]
public void GivenCapacityModelWhenNumMachinesZeroOrLessThenModelShouldBeInvalid()
{
   // Given
   IValidatorThing validator = new ValidatorThing(); //What enforces the rule? Should this be a controller service? Or a decorator such as [Range(0.000001,1000000)]? Doesn't each require different testing methods?
   var invalidModel = new CapacityModel(); // Or the viewmodel?
   double zeroValue = 0.000001;
   invalidModel.NumMachines = zeroValue;

   // When
   var modelIsValid = ValidatorThing.validateModel(invalidModel); 

   // Then
   Assert.IsFalse(modelIsValid);
}

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

  1. Должна ли CapacityModel быть моделью представления? Или DTO из сервисного уровня? Или класс метаданных на уровне DAL? Я могу реализовать любой из них и пройти тест... но что я действительно должен тестировать?
  2. Проверяет ли «валидатор» поведение службы, которая проверяет это свойство модели? Или аннотации данных в CapacityModel? Опять же, что я действительно должен тестировать в контексте трехуровневого приложения?

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

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

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

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

Спасибо,

Лоуренс

РЕДАКТИРОВАТЬ:

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

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


person Chris    schedule 05.12.2015    source источник


Ответы (1)


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

Приемочное тестирование — это то, что очень ориентировано на бизнес-пользователей. Он рассматривает приложение как черный ящик, но проверяет, чтобы интерфейс приложения работал так, как ожидает пользователь.

В вашем примере я бы увидел приемочный тест примерно так:

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

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

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

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

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

person Barnaby Golden    schedule 05.12.2015
comment
Спасибо! Это помогает подтвердить, что я смешиваю две разные концепции. Для контекста я читаю это. Итак, установлено, что для простого бизнес-правила (количество машин должно быть больше нуля) убедитесь, что пользователю предоставляется правильная обратная связь в случае нарушения бизнес-правила. является приемочным тестом, то я бы разложил его на несколько модульных тестов? Например, должно отображаться «недопустимое число», когда X‹0, должно отображаться «обязательно», когда Y пусто? - person Chris; 06.12.2015
comment
Чтобы уточнить предложенное вами решение, теоретически я буду звонить в таблицу базы данных (содержащую коды ошибок) после сообщения об ошибке? Или как-то поймать ошибку, выброшенную Oracle? эта тема обсуждала отлов ошибки от Oracle, но на практике это не похоже на что-то выполнимое. Можете ли вы посоветовать ресурсы, которые подробно описывают реализацию? (возникают проблемы с их поиском, кажется, что информации не так много — может быть, вы что-то знаете?) - person Chris; 06.12.2015
comment
Я ожидаю, что вы будете звонить, чтобы получить сообщение об ошибке. Если бы вы могли вызвать его из исходной ошибки Oracle, это было бы здорово, но я никогда не использовал такую ​​реализацию. Извините, но у меня нет ресурсов, описывающих такую ​​реализацию. По вашему первому пункту: я ожидаю, что приемочный тест проверит механизм сообщения об ошибке, а не все возможные условия ошибки. Но это зависит только от моих взглядов на эффективное использование тестового покрытия. Если вы хотите, чтобы ваше покрытие проверяло все условия, дерзайте! - person Barnaby Golden; 06.12.2015
comment
Спасибо за отзыв, Барнаби. Я полагаю, было бы неплохо, если бы я мог инициировать ошибку от Oracle, но, в конце концов, если сами правила будут выполняться в базе данных, то их повторное тестирование в приложении будет малоценным. Я думаю, было бы более разумно убедиться, что с точки зрения пользователя они каким-то образом предупреждены до POST (поле обязательно), если требуется, и после POST (возможно, с помощью [HandleError (какая-то страница ошибки)] для исключений Таким образом, база данных добавляет ценность с помощью CONSTRAINT, а приложение добавляет ценность с помощью пользовательских сообщений. - person Chris; 06.12.2015