Closed ivanych closed 8 years ago
есть несколько способов. напрашивается использование swat модулей. вот как можно написать
# upstream story - основная история вызывающая downstream story - GET /resource
# название роута неприниципиально, т.к. запрос к серверу делаться не будет
# а response заспуфится через set_response
# читайте далее в исходнике virtual/resource/hook.pm
$ cat virtual/resource/get.txt
done
# upstream story hook
$ cat virtual/resource/hook.pm
# в хуке для основной истории - два раз вызываем downstream story с разными значениями для параметра param:
call_swat_module( GET => '/resource', { value => 'value1' } ); # соответсвует test.ru/resource?param=value1
call_swat_module( GET => 'resource', { value => 'value2' } ); # соответсвует test.ru/resource?param=value2
# так это upstream story, то можно заспуфить ответ сервера, так как в САМОЙ в upstream истории запроса в приложение не происходит, но swat требует, что бы был хоть какой-то ответ, который можно проверить
set_response('done');
# теперь опишем downstream story или swat module
$ cat resource/swat.ini
# объявляем историю модулем:
swat_module=1
curl_params='-G param=%value%'
cat resource/get.txt
200 OK
Подробнее про swat модули можно почитать здесь - https://github.com/melezhik/swat#upstream-and-downstream-stories
Да и соответственно , если хочется делать два разных запроса, нужно просто создать две upstream истории, внутри каждой из которых будет свой вызов ресурса GET /resource, например так:
# virtual/one/hook.pm
call_swat_module( GET => '/resource', { value => 'value1' } );
set_response('done');
# virtual/two/hook.pm
call_swat_module( GET => '/resource', { value => 'value2' } );
set_response('done');
Второй вариант создать два роута, и воспользоваться функцией modify_resource. Он более простой для реализации, но более грубый:
# resource1/hook.pm
modify_resource( sub { '/resource?param=value1' } );
# resource2/hook.pm
modify_resource( sub { '/resource?param=value2' } );
Про функцию modify_resource написано здесь - https://github.com/melezhik/swat#redefine-http-resources
Михаил , получились разобраться с этим ? Пишите , если помощь будет нужна.
Я еще не пробовал, ночь же была:)
Сделал практически один в один как в первом комментарии (только run_swat_module). Но не пойму, как теперь для каждого запроса сделать свой набор тестов. Для обоих запросов вроде как запускается один и тот же набор тестов, из resource/get.txt, а мне надо разные тесты, ведь запросы с разными параметрами возвращают разные ответы.
Второй комментарий про virtual/one/hook.pm и virtual/two/hook.pm я не понял, вроде это ничем не отличается от двух вызовов модуля в одном virtual/resource/hook.pm, как в первом комментарии.
т.е. хочется не только делать разные запросы ( GET '/resource?param=value1' , GET '/resource?param=value2' ), но и по-раному их валидировать ? так?
Да, именно так.
Вроде бы по логике должна быть возможность писать тесты в virtual/resource/hook.pm, а не в resource/get.txt. Можно так сделать?
тогда немного перепишем первый вариант, реализацию resource/get.txt
.
и будем использовать т.н. генераторы проверочных утверждений ( https://github.com/melezhik/outthentic-dsl#generators ) , например так:
$ cat resource/get.txt
# это всегда ведь так?
200 OK
# далее в зависимости от значение переменной value
generator: \
my $v = module_varibale('value'); \
my @list = (); \
push @list, 'value1' if $v eq 'value1' ; \
push @list, 'value2' if $v eq 'value2' ; \
[ @list ]
генератор можно потом будем убрать из get.txt выделить в обычную функцию ( назвать ее как нибудь там assert_for_value ) и написать компактнее:
$ cat resource/get.txt
generator: assert_for_value(module_varibale('value'));
Вроде бы по логике должна быть возможность писать тесты в virtual/resource/hook.pm, а не в resource/get.txt. Можно так сделать?
нет тесты ( проверочные утверждения ) всегда присываются в файлах http методов ( aka check list files ) - get.txt, post.txt и т.д , другой вопрос, что в самих хуках ты можешь определить функции - генераторы и вызвать их в файлах чек листов
Как-то это нехорошо... параметры задаются в хаках, а проверяются в модулях. Т.е. пишу я новый хак - и нужно лезть править модуль. А если хак и модуль пишут разные люди?
что бы было более понятнее можно с использованием хука написать так:
$ cat virtual/resource/hook.pm
call_swat_module(
GET => '/resource',
{
value => 'value1' ,
check_f => sub { ['value1'] }
}
);
call_swat_module(
GET => 'resource',
{
value => 'value2' ,
check_f => sub { ['value2'] }
}
);
set_response('done');
$ cat resource/get.txt
generator: module_varibale('check_f')->()
Как-то это нехорошо... параметры задаются в хуках, а проверяются в модулях. Т.е. пишу я новый хук - и нужно лезть править модуль. А если хук и модуль пишут разные люди?
Михаил, не очень понял последний вопрос, что именно смущает, можете переформулировать?
Хм. Т.е. нужно вводить устное соглашение, что хук (читай - человек, пишущий хук) всегда определяет функцию с заранее оговоренным именем, или вот как выше, создает параметр типа check_f со ссылкой на функцию.
А в модуле эту функцию всегда вызывать.
Мне кажется, было бы удобнее сделать так, чтобы утверждения/тесты задавались в самом хуке, а не в модуле. Чтобы не нужно было гадать - вызовет ли модуль функцию из хука, или не вызовет... Чтобы всегда проверка задавалась там же, где задавались параметры.
Не думали так сделать? Или я ерунду говорю, не до конца разобравшись?
Просто что бы было понимание:
Надеюсь это немного прояснило
Ну, вроде это мне понятно. Но это никак не меняет того, что задание тестов удобнее делать в хуке, а не в модуле.
Сейчас получается так, то модуль сам себе задает тесты. Но модуль же не знает, как и откуда он будет вызван, поэтому и тесты он не может задать адекватно. Предложенный Вами выше способ передачи ему тестов через ссылку на функцию, определенную в хуке, кажется мне обходным путем.
Мне кажется, было бы удобнее сделать так, чтобы утверждения/тесты задавались в самом хуке, а не в модуле. Чтобы не нужно было гадать - вызовет ли модуль функцию из хука, или не вызовет... Чтобы всегда проверка задавалась там же, где задавались параметры. Не думали так сделать? Или я ерунду говорю, не до конца разобравшись?
Мне кажется я понимаю что вы говорите. Но дело в том, что архитектура такова что:
generator: my_cool_check();
Я предлагаю сделать байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука.
Проблема текущей архитектуры в том, что сейчас проверочный файл не знает, где взять уже кем-то написанные проверочные утвержения и есть ли они вообще. Для этого требуется устная договоренность с другими разработчиками, что они будут писать проверочные утверждения и будут называть их оговоренными именами.
Сейчас получается так, то модуль сам себе задает тесты.
Модуль определяет интерфейс и частичную реализацию. Частичная реализация - проверочные утвеждения, определенные внутри проверончого файла модуля:
cat foo/bar/get.txt
200 OK
base_check
Интерфейс - это вызовы вншних проверочных утверждений через генераторы. Внешние проверочные утверждения должны быть определены где-то.
вариации на тему:
cat foo/bar/get.txt
# external_generator() should be defined somewhere else
generator : external_generator()
# module_variable('external_generator_array') is ARRAYRE
generator : module_variable('external_generator_array')
# module_variable('external_generator_f') is CODEREF
generator : module_variable('external_generator_f')->()
Я предлагаю сделай байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука.
они могут оттуда браться, но могу браться как и самого проверочного файла модуля так и и из upstream истории ( варианты я привел ).
Проблема текущей архитектуры в том, что сейчас проверочный файл не знает, где взять уже кем-то написанные проверочные утвержения и есть ли они вообще. Для этого требуется устная договоренность с другими разработчиками, что они будут писать проверочные утверждения и будут называть их оговоренными именами.
Мне кажется у нас возможно разное понимание сути вопроса. Тестовый сценарии обычно пишет один человек. он же определяет всевозможные внешние проверочные утвержения, которые могут быть повторно использованы через генераторы. Т.е. этот человек всегда в курсе о списпке возможностей , которые у него есть. И даже если таких разработчиков несколько - не вижу никакой проблемы .
Если хочется распределить разработку в варианте на который указываете вы, а именно
это возможно и вполне валидно, но даже в этом случае не вижу никаких проблем.
Автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API, автор сват тестов использую эту информацию использует эти утвеждения
Да и мне кажется я догадался к чему вы клонили. Дело в том swat модули являются повторно используемыми только в рамках одного тестового набора (swat проекта) - и не предполагается что они будут использовать кем-то еще в других swat проектах
Т.е. мой основной посыл наверное такой.
Проверочные файлы могут декларировать некий интерфейс для реализации ( вызов внешних проверочных утверждений ). Т.е. я себе с трудом представляю когда кто-то создает проверочный файл в котором существует вызовы внешних проверочных утверждений о которых никто не знает. Как правило, эти внешние проверочные утверждения либо УЖЕ кем-то реализованы - как cpan, perl модули ( см. мой предыдущий пример ) ввиде внешних библиотек, либо ОБЯЗАНЫ быть определены где-то еще внутри проетка и это не тайное знание, т.к. скорее всего тот же кто создает данный проверочный файл , тот же и будет реализовывать внешние проверочные утверждения.
Т.к. все происходит в рамках одного проекта и никто не собирается отдавать данный проверочный файл для повторного использвоания в другой проект ( но даже если это могло быть так - вполне валдиная ситуации очень схожая с термином интерфейс в ОО языках разработки ) - хотя в случае со сватом в этом нет необходимости ...
Хм. Т.е. нужно вводить устное соглашение, что хук (читай - человек, пишущий хук) всегда определяет функцию с заранее оговоренным именем, или вот как выше, создает параметр типа check_f со ссылкой на функцию. А в модуле эту функцию всегда вызывать.
Собственно да. В приведенном вами примере функция вне данного модуля смысла не имеет. Она обязана быть определена, потому что ее уже где-то вызвают. Фактически это обязательный для инициализации параметр модуля.
Я предлагаю сделать байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука
Swat позволяет далать как угодно и в том числе так. Не вижу смысла форсировать такое поведение. Если кому-то нужно он может написать модуль с базовами / дефолтными определениями проверочных утверждений, которые затем можно будет переопределить извне, при вызове данного модуля:
# хук модуля
cat bar/baz/hook.pm
sub baz_check {
return [ module_variable('baz_check') ? module_variable('baz_check')->() : 'baz_check' ]
}
# проверочный файл
# cat bar/baz/get.txt
generator: baz_check();
# хук основной истории
# переопределяем baz_check
run_swat_module(
GET => 'bar/baz/',
{
baz_check => sub { 'ANOTHER_BAZ_CHECK' }
}
)
Тестовый сценарии обычно пишет один человек. он же определяет всевозможные внешние проверочные утвержения, которые могут быть повторно сипользованы через генераторы.
Почему один? У нас, например, несколько тестировщиков. И я хочу описать в модуле интерфейс ресурса, а тестировщики пускай дальше задают параметры и ожидаемые ответы как им заблагорассудится.
Автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API
Это бардак же. Это получается самопальное API поверх API свата. Два разработчика договорятся называть функцию check, а другие два разработчика - test, потом они поменяются местами и при написании новых тестов будут гадать, почему функция в хуке называется check, а из модуля вызывается test.
Нужна гарантия, что описанные в хуке тесты обязательно будут вызваны из модуля и не будут противоречить тестам, которые модуль вдруг сам себе как-то там сгенерирует.
Т.е. я себе с трудом представляю когда кто-то создает проверочный файл в котором существует вызовы внешних проверочных утверждений о которых никто не знает.
Да как же? Именно так всё и должно быть - модуль должен реализовать интерфейс ресурса, а параметры и результаты он проверять не должен, параметры и проверки задает совершенно другой человек, в хуке. Модуль не может знать, какие значения придут в параметрах, и модуль не может знать, какие ответы соответствуют этим параметрам.
Модуль должен просто вызвать функцию проверки из хука.
Собственно, это сейчас и происходит. Вопрос только в том, что имя этой функции сейчас предлагается оговаривать дополнительно, за рамками документации к свату. А я предлагаю задать это имя жестко, и модуль всегда должен вызывать эту функцию из вызвавшего его хука. Более того, если в хуке эта функция определена, то она должна переопределять тесты, заданные в самом модуле, чтобы не возникало конфликтов.
P.S. это всё в рамках одного проекта, я не говорю об использовании сват-модулей в других проектах.
Почему один? У нас, например, несколько тестировщиков. И я хочу описать в модуле интерфейс ресурса, а тестировщики пускай дальше задают параметры и ожидаемые ответы как им заблагорассудится.
Вы видимо меня неправильно поняли. Архитектура swat не противоречет командой разработки кода. Просто в данном конкретном вопросе модуль не является повторно используемой единицей когда ВНЕ своего проекта. Пусть над проектом работает хоть 5 человек, но тот кто создал модуль просто напросто должен обеспечить что бы все внешние проверочные утвержения были реализованы, в частном случае - это сделает сам же автор модуля , но даже если он захочет передать "данный" модуль другим разработчикам он обязан как-то задекларировать требуемый к реализации интерфейс, устно или формально через докуменатацию это уже другой вопрос ... Не вижу с этим никаких проблем.
Просто в данном конкретном вопросе модуль не является повторно используемой единицей когда ВНЕ своего проекта.
Это понятно.
он обязан как-то задекларировать требуемый к реализации интерфейс
Но это можно упростить и повысить надежность - просто задекларировав это на уровне самого свата.
Это бардак же. Это получается самопальное API поверх API свата. Два разработчика договорятся называть функцию check, а другие два разработчика - test, потом они поменяются местами и при написании новых тестов будут гадать, почему функция в хуке называется check, а из модуля вызывается test.
Не очень понял утвердение про "самопальное API поверх API свата" API swat и "API" модуля две совершенно разные вещи. По поводу бардка - мой предыдущий комментарий, не очень понимаю.
Под фразой автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API - я имел ввиду именно библиотеку разработанную вне какого-то модуля. Например можно представить себе набор регэксповых выражений для валидации строк с датами, такой набор регэксп выражений можно выразить ввиде функций, используемых в проверочных файлах swat. Ни какому конкретному модулю эти функции не относятся. Вот имменно таком случае эту библиотеку безопасно сипользовать в разных swat проектах, т.к. она никоем образом не зависит от их структуры и никак не связана с конретными сват модулями. А вот связка функций ( реализующий проверочные утверждения ) для конкрентного модуля о которой я упомянул в предыдущей комметарии - совершенно другое дело - такие функции наружу в другие сват проекты никто выставлять не собиратеся
Но это можно упростить и повысить надежность - просто задекларировав это на уровне самого свата.
Согласен. Как идея принимается. Не уверен что это легко реализовать. Но суть вашего посыла ясна. Будем подумать ...
Да как же? Именно так всё и должно быть - модуль должен реализовать интерфейс ресурса, а параметры и результаты он проверять не должен, параметры и проверки задает совершенно другой человек, в хуке. Модуль не может знать, какие значения придут в параметрах, и модуль не может знать, какие ответы соответствуют этим параметрам.
Ок. Модуль:
Модуль должен просто вызвать функцию проверки из хука. Собственно, это сейчас и происходит. Вопрос только в том, что имя этой функции сейчас предлагается оговаривать дополнительно, за рамками документации к свату. А я предлагаю задать это имя жестко, и модуль всегда должен вызывать эту функцию из вызвавшего его хука. Более того, если в хуке эта функция определена, то она должна переопределять тесты, заданные в самом модуле, чтобы не возникало конфликтов.
Ок. Сейчас уже больше понимания о чем вы говорите ;-) вы предлагаете сделать обязательным реализацию интерфейса модуля на стороне вызвающего кода, в данном случае хука основной истории, и валидировать выполнение этого требования средствами сват. Эта интересная идея. Я подумаю ...
Оке, кажется, договорились:)
Да уж :) . Но пока юзайте в таком виде. Вариантов предостаточно. Над вашей идей надо еще думать ... По первоначальной проблеме ( Несколько разных запросов к одному ресурсу ) вопросы еще есть у вас?
Да, с исходным вопросом всё ясно, я уже сделал, работает, спасибо.
Да, Михаил, я насчет интерфейса модулей думаю создам отдельный тикет . А мне интересно, если не секрет, какой на воде код тестов получается? можно вывести, ну по крайней мере ту часть, которую можно ))
здесь все
Как сделать несколько разных запросов к одному ресурсу? Например, два get-запроса с разными параметрами:
И тесты для разных запросов тоже разные.