Как выполнить модульное тестирование конструкторов

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

  public class Money {public Money (long l)  {this.value = l;  } публичные деньги (String s) {this.value = toLong (s);  } public long getLong () {вернуть this.value;  } public String getString () {return toString (this.value);  }}  

На самом деле существует пара других типов, которые он принимает и в которые преобразует.

Я пытаюсь найти наиболее подходящий способ для проверки этих конструкторов.

Если должен быть тест для каждого конструктора и типа вывода:

  @Testpublic void longConstructor_getLong_MatchesValuePassedToConstructor () {final long  стоимость = 1,00л;  Деньги m = новые деньги (стоимость);  длинный результат = m.getLong ();  assertEquals (value, result);}  

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

Если должно быть несколько утверждений:

  @Testpublic void longConstructor_outputsMatchValuePassedToConstructor () {final  long longValue = 1.00л;  последняя строка stringResult = "1.00";  Деньги m = новые деньги (longValue);  assertEquals (longValue, m.getLong ());  assertEquals (stringResult, m.getString ());}  

У этого есть несколько утверждений, что меня не устраивает. Он также тестирует getString (и через proxy toString), но не указывает это в имени теста. Назвать их еще сложнее.

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

  @Testpublic void getString_MatchesValuePassedToConstructor () {final long value = 1.00;  final String expectedResult = "1.00";  Деньги m = новые деньги (стоимость);  Строка result = m.getLong ();  assertEquals (expectedResult, result);}  

Это устаревший класс, и я не могу изменить исходный класс.


Похоже, у вас есть канонический способ получения «сырого» значения (в данном случае toLong ) — так что просто проверьте правильность всех конструкторов при извлечении это значение. Затем вы можете протестировать другие методы (например, getString () ) на основе одного конструктора, поскольку вы знаете, что после завершения работы различных конструкторов все они оставляют объект в одном и том же состоянии.

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


15

Ожидаемый результат проверки конструктора is: экземпляр был создан

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

  @Test public void testMoneyString () {попробуйте {new Money ("0");  новые деньги («10.0»);  новые деньги ("- 10.0");  } catch (исключение e) {сбой (e.getMessage ());  }} @ Test public void testMoneyStringIllegalValue () {попробуйте {new Money (null);  fail («Ожидалось исключение для нулевого ввода»);  } catch (IllegalArgumentException e) {} попробуйте {новые деньги ("");  fail («Ожидалось исключение для пустого ввода»);  } catch (IllegalArgumentException e) {} попробуйте {новые деньги ("abc");  fail («Исключение ожидалось для нечислового ввода»);  } catch (IllegalArgumentException e) {}}  

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

Улучшить этот ответ
ответил 26 мая 2011 г. в 13:00
добавить комментарий |

Ожидаемый результат теста конструктора: экземпляр был создан

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

  @Test public void testMoneyString () {try {new Money ("0")  ;  новые деньги («10.0»);  новые деньги ("- 10.0");  } catch (исключение e) {сбой (e.getMessage ());  }} @ Test public void testMoneyStringIllegalValue () {попробуйте {new Money (null);  fail («Ожидалось исключение для нулевого ввода»);  } catch (IllegalArgumentException e) {} попробуйте {новые деньги ("");  fail («Ожидалось исключение для пустого ввода»);  } catch (IllegalArgumentException e) {} попробуйте {новые деньги ("abc");  fail («Исключение ожидалось для нечислового ввода»);  } catch (IllegalArgumentException e) {}}  

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


11

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

  @Testpublic void moneyConstructorThatTakesALong { 

Улучшите этот ответ
ответил 26 мая ’11 в 12:48
добавить комментарий |

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

  @Testpublic void moneyConstructorThatTakesALong { 

3

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

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

Улучшите этот ответ
ответил 26 мая ’11 в 12:54
добавить комментарий |

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

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


2

Тестировать конструкторы просто для того, чтобы убедиться, что данные принимают должным образом, не является ПЛОХОЙ идеей, но если вам действительно не нравятся множественные утверждения, разделите их и назовите метод, в котором они делают пример: CanContructorAcceptStringor: CanConstructorAcceptNonLongStringValue

Что-то в этом роде.

Улучшите этот ответ
ответил 26 мая 2011, 12:50
добавить комментарий |

Тестировать конструкторы просто для того, чтобы убедиться, что данные принимают необходимые данные, не является ПЛОХОЙ идеей, но если вам действительно не нравится несколько asserts, разделите их и назовите метод, в котором они делают пример: CanContructorAcceptStringor: CanConstructorAcceptNonLongStringValue

Что-то вроде этого.


0

У вас есть несколько входов (через конструкторы) и несколько выходов (с помощью разных методов getX ()). Но количество членов, которые у него внутри, кажется меньше (в вашем примере 1 длинное значение). Разве не было бы проще сначала протестировать различные входные данные, создав x разные объекты, используя x разные конструкторы. Затем вы можете проверить, все ли они равны, используя реализованный метод equals (). Это можно сделать с помощью одного метода тестирования.

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

Конечно, это требует, чтобы вы реализовали (отдельно тест) метод equals.

В вашем примере я бы создал следующие тестовые наборы:

  @Testpublic void testEquals  () {Деньги m1 = новые Деньги (1);  Деньги m2 = новые Деньги (1);  Деньги m3 = новые Деньги (2);  assertEquals (m1, m2);  assertEquals (m2, m1);  assertNotEquals (m1, m3);  assertNotEquals (m3, m1);  assertNotEquals (m1, null);} private void testConstructors (long lValue, String sValue) {Money m1 = new Money (lValue);  Деньги m2 = новые деньги (sValue);  assertEquals (m1, m2);} @ Testpublic void testConstructorsPositive () {testConstructors (1, "1");} @ Testpublic void testConstructorsNegative () {testConstructors (-1, "-1");} @ Testpublic void testConstructorsZero ()  {testConstructors (0, "0");} @ Testpublic void testGet ... () {/* и т. д. */}  

Улучшить этот ответ
ответил 26 мая 2011 в 13:04
  • Если конструктор ничего не делает, все тесты проходят, потому что money = 0. — Петр Перак, 26 мая. ’11 в 20:17
  • Тесты testGet … () завершатся ошибкой, если конструктор ничего не сделает. — Марк 27 мая ’11 в 12:08
добавить комментарий |

У вас есть несколько входов (через конструкторы) и несколько выходов (через разные методы getX ()). Но количество членов, которые у него внутри, кажется меньше (в вашем примере 1 длинное значение). Разве не было бы проще сначала протестировать разные входные данные, создав x разные объекты, используя x разные конструкторы. Затем вы можете проверить, все ли они равны, используя реализованный метод equals (). Это можно сделать с помощью одного метода тестирования.

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

Конечно, это требует от вас реализации (отдельного теста) метода equals.

В вашем примере я бы создал следующие тестовые наборы:

  @Testpublic void testEquals () {Money m1 = new Money (1);  Деньги m2 = новые Деньги (1);  Деньги m3 = новые Деньги (2);  assertEquals (m1, m2);  assertEquals (m2, m1);  assertNotEquals (m1, m3);  assertNotEquals (m3, m1);  assertNotEquals (m1, null);} private void testConstructors (long lValue, String sValue) {Money m1 = new Money (lValue);  Деньги m2 = новые деньги (sValue);  assertEquals (m1, m2);} @ Testpublic void testConstructorsPositive () {testConstructors (1, "1");} @ Testpublic void testConstructorsNegative () {testConstructors (-1, "-1");} @ Testpublic void testConstructorsZero ()  {testConstructors (0, "0");} @ Testpublic void testGet ... () {/* и т. д. */}  

-1

Конструктор — это инициализатор объекта. Тестирование конструктора — это проверка факта инициализации. То есть проверка того, что поля объекта были инициализированы значениями, переданными конструктору. И это можно проверить только путем отражения.

Улучшите этот ответ
ответил 09 нояб. в 16:57
добавить комментарий |

Конструктор — это инициализатор объекта. Тестирование конструктора — это проверка факта инициализации. То есть проверка того, что поля объекта были инициализированы значениями, переданными конструктору. И это можно проверить только с помощью отражения.



Модульные тесты для конструкторов

Если я создам класс, то в конструктор принимает массив или коллекцию, но этот массив или коллекция необязательны (параметр может иметь значение NULL), а затем я сохраняю эту коллекцию в рассматриваемом объекте, в конструкторе мне нужно что-то вроде:

  this.coll = coll == null?  null: coll.clone ();  

Стоит ли проводить модульное тестирование такого кода? например, проверить, работает ли он при передаче нуля или нет?


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

  this.coll = coll == null?  null: coll.clone ();  
  • Возможно, вы забыли использовать параметр coll , т.е. приведенное выше утверждение отсутствует. Это можно проверить с помощью теста, который зависит от coll , предоставленного конструктору.

  • Возможно, вы забыли клонировать параметр:

      this.coll = coll;  

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

  • Возможно, вы забыли обработать нулевой регистр:

       this.coll = coll.clone ();  

    Это можно проверить с помощью теста, который пропускает этот параметр/предоставляет нулевое значение. Обычно мы ожидаем исключения, здесь null — это нормально.

  • Еще одна вещь, которая может пойти не так, — это то, что вы создаете нулевой объект или экземпляр по умолчанию, когда встречается null, например:

      this.coll = coll == null?  new Collection (): coll.clone ();  

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

Это уже четыре тестовых случая, которые были бы разумными для этой простой строки кода. Использование инструмента покрытия кода может помочь в обнаружении невыявленных случаев в вашем коде, в частности, если вы также посмотрите на покрытие ветвей. У некоторых инструментов есть проблемы с потоком управления на уровне выражения ( ?: , && , || ), поэтому так лучше (и более удобочитаемыми для людей!) для использования условных выражений на уровне операторов:

  if (coll! = null) {coll = coll.clone ();} this.  coll = coll;  

1

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

Практически любое поведение, которое вы ожидаете от класса является кандидатом на модульное тестирование. Это верно и для конструкторов.

Улучшите этот ответ
отредактировано 28 января ’17 в 16:39
ответил 28 января ’17 в 16:31
  • вы знаете, это случай, когда null и не null — это нормально, и единственная причина, по которой мне нужно что-либо тестировать, — это то, что вы не можете просто this.col = col, так как это будет разделять базовый массив или коллекцию, и это опасно, поэтому ему нужен условный клон . — Михал Зеган 28 янв. ’17 в 17:56
добавить комментарий |

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

Практически любое поведение, которое вы ожидаете от класса, является кандидатом для модульного тестирования. Это верно и для конструкторов.

Оцените статью
logicle.ru
Добавить комментарий