2013-09-26 2 views
5

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

public void testAdd() { 
    BoundedPriorityBlockingQueue q = BoundedPriorityBlockingQueue(); 
    q.add(1); 
    assertEquals(1, q.size()); 
} 

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

+0

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

+2

@Grove: Это было бы гораздо более хрупким, чем использование 'size()', IMO. Он будет опираться на детали реализации. –

+0

@ Jon Я частично согласен, так как, если я не ошибаюсь, модульное тестирование должно быть проведено с использованием белого ящика. – Morfic

ответ

11

Какова наилучшая практика в этой ситуации?

Просто сосать его, учитывая, что тесты предназначены для вас, а не наоборот.

Будут ли ваши тесты ломаться, если что-то пойдет ужасно неправильно? Да.

Будет ли ясно, где проблема? Вероятно, учитывая, что что-либо, использующее size, потерпит неудачу.

Этот тест ведет вас к менее проверяемому дизайну? №

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

Да, это своего рода тестирование двух частей того же класса, но я действительно не думаю, что это проблема. Я вижу много догм вокруг тестирования («только когда-либо проверяйте публичный API, всегда используйте AAA» и т. Д.) - по моему опыту вы должны умерить этот догматизм со здоровой дозой прагматизма.

6

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

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

2

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

Во всяком случае, если вы все еще заинтересованы в имеющих такую ​​независимость между тестами вы могли бы пойти на белого ящик тестирования стратегии: Я думаю, что ваш BoundedPropertyBlockingQueue использует внутренне либо любой из java.util коллекций, массива или коллекции от других поставщиков (Guava, Apache Collections и т. д.), на которые вы полагаетесь, поэтому вам не нужно проверять, что эти структуры работают так, как они должны делать.

Таким образом, определить, что внутренняя структура, как protected поместите тестовый класс в пакете с тем же именем, и, вместо того, чтобы полагаться на реализацию метода size, перейдите в кишках BoundedPropertyBlockingQueue:

BoundedPriorityBlockingQueue q = BoundedPriorityBlockingQueue(); 
q.add(1); 
assertEquals(1, q.contents.size()); // assuming that `contents` attribute is a collection. 

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

IMO Я бы выбрал вашу текущую реализацию, менее связанную и, в конце концов, выполняет свою задачу.

1

Нет ничего плохого в том, что вы делаете такое перекрестное тестирование - некоторые методы имеют тенденцию жить в парах (добавление/удаление, удаление/удаление и т. Д.), И нет смысла тестировать один без его дополнительной части.

Однако я бы немного подумал о том, как ваш add метод будет использоваться вашими клиентами (пользователями класса). Скорее всего, не будет вызывать add только для определения того, изменился ли размер, а скорее для последующего извлечения добавленного элемента. Может быть, ваш тест должен выглядеть следующим образом:

BoundedPriorityBlockingQueue q = new BoundedPriorityBlockingQueue(); 
QueueItem toAdd = 1; 
QueueItem added = q.dequeue(); 
assertEquals(toAdded, added); 

Кроме того, вы также можете добавить guard assert к тесту выше (для обеспечения очереди не начать с некоторыми пунктами уже добавлен), или даже лучше - включать отдельный тест который гарантирует начальное состояние очереди (размер равен 0, dequeue возвращает null/throwing).

Смежные вопросы