Есть функция для работы с переменной (полем) “Возраст студента”. КАК спроектировать для этой функции любые кейсы (тесты) для верификации?
if (!studentAge.matches("\\d+") ||
Integer.parseInt(studentAge) < 5 ||
Integer.parseInt(studentAge) > 65) {
System.out.println("Invalid Age!");
}
Тесты - это контракт.
Для того чтобы спроектировать тесты, необходимо знать что должна делать функция и чего не должна.
В Вашем случае необходимо убедиться что функция делает то что Вы задумали - проверяет возраст студента.
Вот Ваш пример, в виде класса
public class Student {
private String studentAge;
public Student(String studentAge) {
this.studentAge = studentAge;
}
public void checkAgeError() {
if (!studentAge.matches("\\d+") ||
Integer.parseInt(studentAge) < 5 ||
Integer.parseInt(studentAge) > 65) {
System.out.println("Invalid Age!");
}
}
}
Я назвал функцию checkAgeError()
формальные unit-тесты для нее написать будет сложно т.к. функция содержит System.out
которая является сайд эффектом (side effect), для этой функции (т.к. название не отражает то, что функция что-то выведет) хоть и тип возвращаемого значение void
неявно нам на это намекает. Но проблема не в наличии сайд эффекта а в его характере - вывод в консоль это IO
(общение с подсистемой ввода-вывода)
и ссылка на это поле использована статическая.
Что в этом плохого - как раз то, что cложно написать тест для этой функции, чтобы убедиться что она отработала корректно Вам необходимо иметь дело со статическим полем класса System
, это сильно повезло что System.out
можно перезадать на свой OutputStream
, а не на вывод в консоль и узнать что туда было записано в рамках вызова тестового метода.
Чтобы этого не делать надо немного перепроектировать функцию, чтобы она возвращала результат проверки, а не выводила текст в консоль.
public void checkAgeError() {
return !studentAge.matches("\\d+") ||
Integer.parseInt(studentAge) < 5 ||
Integer.parseInt(studentAge) > 65;
}
Теперь выводить в консоль нужно в том месте, где вызывается функция checkAge()
а не внутри нее, и мы можем легко написать unit-тесты к этой функции.
Какой тут контракт?
Так как логика функции инвертирована (проверяем некорректность а не корректность :) ) необходимо проверить, что при корректных входных значениях даст отрицательный результат а в некорректных - положительный, это и сделаем, в этом примере код для тестового фреймворка JUnit4:
import org.junit.Test;
import static org.junit.Assert.*;
public class StudentTest {
@Test
public void checkAgeDataType() {
assertTrue( "must return true when age is not number",
new Student("").checkAgeNotMatch());
}
@Test
public void checkAgeMin() {
assertTrue( "must return true when age is lower than 5",
new Student("4").checkAgeNotMatch());
}
@Test
public void checkAgeMax() {
assertTrue( "must return true when age is greater than 65",
new Student("66").checkAgeNotMatch());
}
@Test
public void checkAgeInterval6() {
assertFalse( "must return false when age is number between 5 and 65",
new Student("6").checkAgeNotMatch());
}
@Test
public void checkAgeInterval64() {
assertFalse( "must return false when age is number between 5 and 65",
new Student("64").checkAgeNotMatch());
}
// так же возможно проверка поведения с выбросом исключения
@Test(expected = NullPointerException.class)
public void checkAgeIsNull() {
assertTrue( "must throw npe when number is null",
new Student(null).checkAgeNotMatch());
}
}
Теперь, когда функция checkAgeNotMatch
сломается по какой-либо причине, должен упасть какой-о из тестов, но для этого нужно их постоянно запускать
PS: это очень простой пример, тут нет mock
объектов, которым можно было бы закрыть System.out
, однако не буду я тут писать целую книгу..., извините что может быть слегка сумбурно, давайте вместе поправим, если что-то запутано написано =)
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
Пишу небольшой 2D шутер, на данный момент герой поворачивается в ту сторону куда смотрит мышь, не могу понять как сделать так чтобы он двигался...
как сделать OnClick в моем адаптереодна кнопка если на нее нажали то должно происходить какое то действие
Как написать метод,который помещает в Коллекцию сразу все объект(а не по одному)? Есть класс Products с конструктором и переопределением toString...