Плохо ли рассчитывать на порядок ваших модульных тестов NUnit? - PullRequest
15 голосов
/ 31 января 2009

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

Можете ли вы даже определить порядок тестов в NUnit или они всегда выполняются в алфавитном порядке?

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

Обновление: Спасибо всем, кто ответил - было много хороших ответов, и смысл группы довольно единодушен. Я выбрал ответ Джона Нолана, так как он дал самое полное объяснение и множество ссылок. Как вы уже догадались, мне очень хотелось нарушить это правило, несмотря на мысль, что, как выразился Джон, оно может быть немного «вонючим». Также спасибо Fortyrunner за добавление тега unit-testing .

Ответы [ 8 ]

11 голосов
/ 31 января 2009

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

10 голосов
/ 31 января 2009

Опираясь на порядок ваших тестов, указывает, что вы сохраняете состояние в тестах. Это вонючий

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

Хороший способ подумать о приближающихся модульных тестах - шаблон Arrange, Act, Assert .

Ниже приведен фрагмент прекрасной бесплатной электронной книги Карла Сегуина . Я комментировал Arrange, Act и Assert.

[TestFixture] public class CarTest 
{ 
    [Test] public void SaveCarCallsUpdateWhenAlreadyExistingCar()   
    {
         //Arrange
         MockRepository mocks = new MockRepository();
         IDataAccess dataAccess = mocks.CreateMock<IDataAccess>();   
         ObjectFactory.InjectStub(typeof(IDataAccess), dataAccess); 
         //Act
         Car car = new Car(); 
         Expect.Call(dataAccess.Save(car)).Return(389); 
         mocks.ReplayAll(); 
         car.Save(); 
         mocks.VerifyAll(); 
         // Assert
         Assert.AreEqual(389, car.Id); 
         ObjectFactory.ResetDefaults();
    } 
}
8 голосов
/ 31 января 2009

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

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

6 голосов
/ 31 января 2009

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

3 голосов
/ 31 января 2009

Я бы настоятельно рекомендовал сделать все ваши юнит-тесты независимыми.

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

Кроме того, один проваленный юнит-тест не должен утащить многих других (которые могут прекрасно работать самостоятельно).

3 голосов
/ 31 января 2009

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

2 голосов
/ 31 января 2009

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

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

Было бы очень неразумно зависеть от порядка (наборов) тестов в разных файлах.

2 голосов
/ 31 января 2009

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

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