Пообщался сегодня с одним из наших архитекторов. Очень интересный разговор получился. Его месседж был следующим:
«Тесты должны выполнять операции так как они заимплементированы в коде, без всяких там врапперов для них»
Обоснование было таким:
«За врапперами скрывается реальная имплементация, что может привести к багам в тестах, если врапперы не повторяют на 100% того, как выполняется операция»
Очень сложно не согласиться с этой точкой зрения. Тест должен быть правильным, должен выполнять операции так, как они заимплементированы. Когда мы пишем UI тесты, так и происходит, т.к. мы оперируем лишь с контролами, и уже они вызывают операции. Но когда тесты выполняются на уровне API, все становится уже не так просто.
Приведу небольшой пример:
Нужен был тест, который выполняет операцию рассчета некоторых данных и потом уже проверяет её. Пишем следующий код:
public void testCalculation(int param1, int param2) { Operation operation = new CalculateOperation(param1, param2); assertTrue(operation.execute(), “Execution failed”); }
Вроде все ОК, но потом кто-то тестом находит «баг», что для некоторых значений калькуляция не работает. А тест этого не находит. Почему же? Копаем код и оказывается, что в приложении перед калькуляцией происходит валидация данных. Добавляем:
public void testCalculation(int param1, int param2) { Operation operation = new CalculateOperation(param1, param2); assertTrue(operation.validate(), “Validation failed”); assertTrue(operation.execute(), “Execution failed”); }
Обращаем внимание, что подобная структура присутствует в нескольких тестовых методах, решаем вынести это в отдельный метод:
public boolean runOperation(Operation operation) { assertTrue(operation.validate(), “Validation failed”); return operation.execute(); } public void testCalculation(int param1, int param2) { Operation operation = new CalculateOperation(param1, param2); assertTrue(runOperation (operation), “Execution failed”); }
Выглядит вроде хорошо – все довольны. Но потом оказывается, что некоторые калькуляции надо запускать без валидаций, создаем еще один враппер.
public boolean runOperationWithValidation(Operation operation) { assertTrue(operation.validate(), “Validation failed”); return operation.execute(); } public boolean runOperationWithoutValidation(Operation operation) { return operation.execute(); }
Потом появляются дополнительные условия, и у нас уже 3-4-5 врапперов для запуска операции. И тут мы начинаем задумывать, какой именно враппер нам использвовать. Приходится лезть глубоко в код и разбираться в имплементации той или иной операции, чтобы выбрать в итоге нужный враппер.
Все может быть и нормально, когда у вас код написан на одном языке. А если их несколько? Если операци написана на C++, а вызывается из С# или какого javascript кода?
К чему я это все веду – не тестровщицкое это дело писать тесты на уровне API. На уровне UI – пишите, вы хозяева UI тестирования. Если же у вас есть желание разобраться с кодом приложения, вам это нравится, и у вас это хорошо получается, то дам вам совет – ищите работу девелопера (Software Developer), на худой конец, если без тестирования вы никак не можете, то тест девелопера (Software Developer in Test).
Тестирование - это не про код, это про работу приложения.
Комментариев нет:
Отправить комментарий