Многие статьи и книги уже написаны о паттернах модульного тестирования и анти-шаблонах. Я хочу добавить еще одну рекомендацию, которая, как мне кажется, может помочь нам сделать наши тесты и наш производственный код более объектно-ориентированными. Вот он: тестовый метод не должен содержать ничего, кроме одного утверждения.
Посмотрите на этот тестовый метод из RandomStreamTest из OpenJDK 8, созданный Брайаном Гетцем:
@Test
public void testIntStream() {
final long seed = System.currentTimeMillis();
final Random r1 = new Random(seed);
final int[] a = new int[SIZE];
for (int i=0; i < SIZE; i++) {
a[i] = r1.nextInt();
}
final Random r2 = new Random(seed);
final int[] b = r2.ints().limit(SIZE).toArray();
assertEquals(a, b);
}
В этом методе есть две части: алгоритм и утверждение. Алгоритм подготавливает два массива целых чисел, и утверждение сравнивает их и выдает AssertionError, если они не равны.
Я говорю, что первая часть, алгоритм, та, которую мы должны стараться избегать. Единственное, что мы должны иметь - это утверждение. Вот как я хотел бы изменить этот метод тестирования:
Я говорю, что первая часть, алгоритм, та, которую мы должны стараться избегать. Единственное, что мы должны иметь - это утверждение. Вот как я хотел бы изменить этот метод тестирования:
@Test
public void testIntStream() {
final long seed = System.currentTimeMillis();
assertEquals(
new ArrayFromRandom(
new Random(seed)
).toArray(SIZE),
new Random(seed).ints().limit(SIZE).toArray()
);
}
private static class ArrayFromRandom {
private final Random random;
ArrayFromRandom(Random r) {
this.random = r;
}
int[] toArray(int s) {
final int[] a = new int[s];
for (int i=0; i < s; i++) {
a[i] = this.random.nextInt();
}
return a;
}
}
Если бы у Java были прозвища (monikers), этот код выглядел бы еще элегантнее:
@Test
public void testIntStream() {
assertEquals(
new ArrayFromRandom(
new Random(System.currentTimeMillis() as seed)
).toArray(SIZE),
new Random(seed).ints().limit(SIZE).toArray()
);
}
Как вы можете видеть, в этом методе есть только одно «утверждение»: assertEquals ().
Hamcrest с его assertThat () и его набором основных сопоставлений является идеальным инструментом, чтобы наши методы тестирования с одним утверждением были еще более сплоченными и читаемыми.
Есть ряд практических преимуществ этого принципа, если мы согласны следовать ему:
Повторное использование. Классы, которые мы будем создавать для тестовых утверждений, могут быть повторно использованы в других тестах и тестовых случаях. Так же, как в приведенном выше примере ArrayFromRandom может использоваться где-то в другом месте. Аналогично, сопоставители Hamcrest могут и будут представлять собой библиотеку компонентов многократно используемых тестов.
Краткость. Так как создать длинный тестовый метод довольно сложно, если у него есть только одно утверждение, вы и ваши коллеги-программисты неизбежно напишете более короткий и читаемый код.
Читаемость. С одним утверждением всегда будет очевидно, какова цель метода тестирования. Он начнется с объявления намерения, в то время как все остальные детали нижнего уровня будут с отступом.
Неизменность. Будет почти невозможно иметь сеттеры в производственном коде, если в методах тестирования нет места для алгоритмического кода. Вы неизбежно создадите неизменяемые объекты, чтобы сделать их тестируемыми с помощью одного утверждения.
Самое большое преимущество, которое мы получаем, когда этот принцип применяется к нашим тестам, состоит в том, что они становятся декларативными и объектно-ориентированными, а не алгоритмическими, императивными и процедурными.
Hamcrest с его assertThat () и его набором основных сопоставлений является идеальным инструментом, чтобы наши методы тестирования с одним утверждением были еще более сплоченными и читаемыми.
Есть ряд практических преимуществ этого принципа, если мы согласны следовать ему:
Повторное использование. Классы, которые мы будем создавать для тестовых утверждений, могут быть повторно использованы в других тестах и тестовых случаях. Так же, как в приведенном выше примере ArrayFromRandom может использоваться где-то в другом месте. Аналогично, сопоставители Hamcrest могут и будут представлять собой библиотеку компонентов многократно используемых тестов.
Краткость. Так как создать длинный тестовый метод довольно сложно, если у него есть только одно утверждение, вы и ваши коллеги-программисты неизбежно напишете более короткий и читаемый код.
Читаемость. С одним утверждением всегда будет очевидно, какова цель метода тестирования. Он начнется с объявления намерения, в то время как все остальные детали нижнего уровня будут с отступом.
Неизменность. Будет почти невозможно иметь сеттеры в производственном коде, если в методах тестирования нет места для алгоритмического кода. Вы неизбежно создадите неизменяемые объекты, чтобы сделать их тестируемыми с помощью одного утверждения.
Самое большое преимущество, которое мы получаем, когда этот принцип применяется к нашим тестам, состоит в том, что они становятся декларативными и объектно-ориентированными, а не алгоритмическими, императивными и процедурными.
Комментариев нет:
Отправить комментарий