В текущем проекте, над которым я работаю, мы используем множество интеграционных тестов. Для тех, кто не является пользователем 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 в Дублине . |