Пара вопросов о юнит-тестировании - PullRequest
1 голос
/ 30 августа 2010

Давайте предположим, что мы проектируем класс стека первым (TDD):

public class Stack<T> {
    private T[] elements = new T[16];
    private int size = 0;
    ...
}

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

Сначала я выбрал что-то вроде:

Should_Be_Able_To_Correctly_Increase_Its_Inner_Array_Size()

, а затем

Should_Handle_More_Items_Than_The_Default_Internal_Array_Size()

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

Should_Double_Its_Size_Every_Time_Its_Full()

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

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

Что приводит меня к моему второму вопросу : Предполагая, что я выполнил все юнит-тесты для своего класса Stack, который использует внутренний массив, и он работает нормально и, как ожидается, мои тесты останутся нетронутыми, если я позже Хотите реорганизовать и изменить массив на ArrayList или любой другой вид структуры данных? Или тесты должны как-то это отражать? Я думаю, нет, но я не уверен.

Ответы [ 4 ]

3 голосов
/ 30 августа 2010

На мой взгляд (я не уверен, что я правильно), мои тесты должны возможны взаимодействия моего SUT с экстерьер, а не о том, как это реализовано внутри. Я прав?

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

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

2 голосов
/ 30 августа 2010

Спросите себя, что вы готовы совершить для этого класса.

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

public Stack<T>(CapacityGrowthStyle capacityGrowthStyle) { ... }

Если нет, просто напишите тесты для документирования емкости и оставьте это там (где X нижепредел вашей базовой структуры данных):

[Test]
public void Can_Handle_X_Items() { ... }

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void Cannot_Handle_More_Than_X_Items() { ... }

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

2 голосов
/ 30 августа 2010

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

Ответ на ваш второй вопрос - да, тест все равно должен пройти, если это юнит-тест.

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

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

...