В текущем проекте, над которым я работаю, мы используем множество интеграционных тестов. Для тех, кто не является пользователем Grails, интеграционные тесты проверяют ваши API-интерфейсы контроллера, ваши службы и все возможности, которые могут произойти очень аккуратно. Единственный кусок пирога, который они не тестируют с внутренней стороны, — это ваши фильтры Grails, для которых вам нужно что-то вроде функционального теста . В мире Grails API-интерфейсы контроллера отображаются на URL-запросы в файле URLMappings.groovy . Это простой Groovy для настройки того, какой HTTP-запрос отправляется на какой контроллер.
Например:
|
1
2
3
4
|
class UrlMappings { static mappings = { "/sports/rugby/ball" (controller: "rugbyBall", action = [POST: "createBall", DELETE: "removeBall", GET: "getBall"]) ... |
Таким образом, в приведенном выше примере HTTP-запрос /sports/rugby/ball перейдет к RugbyBallController и перейдет к методам: createBall(), deleteBall(), getBall() зависимости от того, является ли GET, POST или DELETE , Теперь предположим, что ваш проект полностью настроен на сервер для операций CRUD для мяча по регби, и после нескольких суетливых спринтов возникает некоторая программная энтропия, и вам нужно реорганизовать свои API-интерфейсы контроллера, но прежде чем вы начнете двигаться вперед и сделаете так, чтобы ваш менеджер проекта посмотрел вы в глаза и говорите: «Вы должны поддерживать все существующие API, так как клиенты их используют».
Вот как обычно рефакторинг работает в реальном мире, когда все идет в производство. Всегда есть этап поддержки старого и нового, осуждающий старое, а затем, когда все счастливы, удаляя его. В любом случае, вы начинаете с обновления вашего URLMappings.groovy
|
1
2
3
4
5
6
7
8
9
|
class UrlMappings { static mappings = { // Old APIs "/sports/rugby/ball" ( controller: "rugbyBall", action = [POST: "oldCreateBall", DELETE: "oldRemoveBall", GET: "oldGetBall"]) ... // New APIs "/sports/rugby/v2/ball" ( controller: "rugbyBall", action = [POST: "createBall", DELETE: "removeBall", GET: "getBall"]) ... |
URLMappings.groovy покажет старое и новое. Старые API собираются для методов контроллера, которые вы переименовали. На клиентов, использующих эти API-интерфейсы, это не влияет, поскольку они отправляют только HTTP-запросы, они не знают, какой контроллер находится за этими конечными точками. У старых API уже есть действительно хорошие интеграционные тесты, и наш менеджер проекта поручил, чтобы у новых API были аналогичные качественные интеграционные тесты, прежде чем они начнут готовиться к производству.
|
1
2
3
4
5
6
7
8
9
|
def "test adding a single item to your cart"() { setup: "Set up the Cart and Landing Controller" //... when: //... rugbyBallController.oldGetBall(); rugbyBall = JSON.parse(rugbyBallController.response.contentAsString) then: rugbyBall.isOval(); |
Г-н Менеджер проекта говорит: «Я хочу, чтобы все эти новые тесты были добавлены к пятнице, иначе вы не собираетесь пинту после работы. Вам нужен быстрый способ сделать ваши интеграционные тесты ». Думая об этом крутом лагере и его эффекте подавления в задней части горла, вы помните отличную поддержку Groovy для динамического вызова методов, где вы можете указать имя метода в качестве переменной.
|
1
|
myObject."$myMethod"() // myMethod is a Groovy String variable. |
В приведенном выше фрагменте кода myMethod — это переменная, которая соответствует имени метода, который вы хотите вызвать в myObject . «$ MyMethod» означает, что оценивать переменную myMethod (которая, конечно, будет именем метода), конечно, означает, что () вызывает метод. Эврика случается, когда вы вспоминаете, что старый и новый API возвращают одинаковый JSON. Все, что вам нужно сделать, это запустить один и тот же тест дважды, один раз для старого кода и один раз для нового. Поскольку для интеграционных тестов вы используете каркас спока , это легко достигается с помощью блока where .
|
01
02
03
04
05
06
07
08
09
10
11
|
def "test adding a single item to your cart"(String method) { setup: "Set up the Cart and Landing Controller" //... when: //... rugbyBallController."$method"(); rugbyBall = JSON.parse(rugbyBallController.response.contentAsString) then: rugbyBall.isOval(); where: method = ["oldGetBall", "getBall"] |
Счастливые дни. А теперь иди и выпей этот лагер.
| Ссылка: | Совет Grails: рефакторинг ваших URL-адресов от нашего партнера JCG Алекса Стейвли в блоге Techlin в Дублине . |