melezhik / swat

Simple Web Application Test
48 stars 12 forks source link

Несколько разных запросов к одному ресурсу #7

Closed ivanych closed 8 years ago

ivanych commented 8 years ago

Как сделать несколько разных запросов к одному ресурсу? Например, два get-запроса с разными параметрами:

test.ru/resource?param=value1
test.ru/resource?param=value2

И тесты для разных запросов тоже разные.

melezhik commented 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

melezhik commented 8 years ago

Да и соответственно , если хочется делать два разных запроса, нужно просто создать две 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');
melezhik commented 8 years ago

Второй вариант создать два роута, и воспользоваться функцией 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

melezhik commented 8 years ago

Михаил , получились разобраться с этим ? Пишите , если помощь будет нужна.

ivanych commented 8 years ago

Я еще не пробовал, ночь же была:)

ivanych commented 8 years ago

Сделал практически один в один как в первом комментарии (только run_swat_module). Но не пойму, как теперь для каждого запроса сделать свой набор тестов. Для обоих запросов вроде как запускается один и тот же набор тестов, из resource/get.txt, а мне надо разные тесты, ведь запросы с разными параметрами возвращают разные ответы.

Второй комментарий про virtual/one/hook.pm и virtual/two/hook.pm я не понял, вроде это ничем не отличается от двух вызовов модуля в одном virtual/resource/hook.pm, как в первом комментарии.

melezhik commented 8 years ago

т.е. хочется не только делать разные запросы ( GET '/resource?param=value1' , GET '/resource?param=value2' ), но и по-раному их валидировать ? так?

ivanych commented 8 years ago

Да, именно так.

ivanych commented 8 years ago

Вроде бы по логике должна быть возможность писать тесты в virtual/resource/hook.pm, а не в resource/get.txt. Можно так сделать?

melezhik commented 8 years ago

тогда немного перепишем первый вариант, реализацию 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'));
melezhik commented 8 years ago

Вроде бы по логике должна быть возможность писать тесты в virtual/resource/hook.pm, а не в resource/get.txt. Можно так сделать?

нет тесты ( проверочные утверждения ) всегда присываются в файлах http методов ( aka check list files ) - get.txt, post.txt и т.д , другой вопрос, что в самих хуках ты можешь определить функции - генераторы и вызвать их в файлах чек листов

ivanych commented 8 years ago

Как-то это нехорошо... параметры задаются в хаках, а проверяются в модулях. Т.е. пишу я новый хак - и нужно лезть править модуль. А если хак и модуль пишут разные люди?

melezhik commented 8 years ago

что бы было более понятнее можно с использованием хука написать так:

$ 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')->()
melezhik commented 8 years ago

Как-то это нехорошо... параметры задаются в хуках, а проверяются в модулях. Т.е. пишу я новый хук - и нужно лезть править модуль. А если хук и модуль пишут разные люди?

Михаил, не очень понял последний вопрос, что именно смущает, можете переформулировать?

ivanych commented 8 years ago

Хм. Т.е. нужно вводить устное соглашение, что хук (читай - человек, пишущий хук) всегда определяет функцию с заранее оговоренным именем, или вот как выше, создает параметр типа check_f со ссылкой на функцию.

А в модуле эту функцию всегда вызывать.

ivanych commented 8 years ago

Мне кажется, было бы удобнее сделать так, чтобы утверждения/тесты задавались в самом хуке, а не в модуле. Чтобы не нужно было гадать - вызовет ли модуль функцию из хука, или не вызовет... Чтобы всегда проверка задавалась там же, где задавались параметры.

Не думали так сделать? Или я ерунду говорю, не до конца разобравшись?

melezhik commented 8 years ago

Просто что бы было понимание:


Надеюсь это немного прояснило

ivanych commented 8 years ago

Ну, вроде это мне понятно. Но это никак не меняет того, что задание тестов удобнее делать в хуке, а не в модуле.

Сейчас получается так, то модуль сам себе задает тесты. Но модуль же не знает, как и откуда он будет вызван, поэтому и тесты он не может задать адекватно. Предложенный Вами выше способ передачи ему тестов через ссылку на функцию, определенную в хуке, кажется мне обходным путем.

melezhik commented 8 years ago

Мне кажется, было бы удобнее сделать так, чтобы утверждения/тесты задавались в самом хуке, а не в модуле. Чтобы не нужно было гадать - вызовет ли модуль функцию из хука, или не вызовет... Чтобы всегда проверка задавалась там же, где задавались параметры. Не думали так сделать? Или я ерунду говорю, не до конца разобравшись?

Мне кажется я понимаю что вы говорите. Но дело в том, что архитектура такова что:

   generator: my_cool_check();
ivanych commented 8 years ago

Я предлагаю сделать байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука.

ivanych commented 8 years ago

Проблема текущей архитектуры в том, что сейчас проверочный файл не знает, где взять уже кем-то написанные проверочные утвержения и есть ли они вообще. Для этого требуется устная договоренность с другими разработчиками, что они будут писать проверочные утверждения и будут называть их оговоренными именами.

melezhik commented 8 years ago

Сейчас получается так, то модуль сам себе задает тесты.

Модуль определяет интерфейс и частичную реализацию. Частичная реализация - проверочные утвеждения, определенные внутри проверончого файла модуля:

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')->()
melezhik commented 8 years ago

Я предлагаю сделай байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука.

они могут оттуда браться, но могу браться как и самого проверочного файла модуля так и и из upstream истории ( варианты я привел ).

melezhik commented 8 years ago

Проблема текущей архитектуры в том, что сейчас проверочный файл не знает, где взять уже кем-то написанные проверочные утвержения и есть ли они вообще. Для этого требуется устная договоренность с другими разработчиками, что они будут писать проверочные утверждения и будут называть их оговоренными именами.

Мне кажется у нас возможно разное понимание сути вопроса. Тестовый сценарии обычно пишет один человек. он же определяет всевозможные внешние проверочные утвержения, которые могут быть повторно использованы через генераторы. Т.е. этот человек всегда в курсе о списпке возможностей , которые у него есть. И даже если таких разработчиков несколько - не вижу никакой проблемы .

Если хочется распределить разработку в варианте на который указываете вы, а именно

это возможно и вполне валидно, но даже в этом случае не вижу никаких проблем.

Автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API, автор сват тестов использую эту информацию использует эти утвеждения

Да и мне кажется я догадался к чему вы клонили. Дело в том swat модули являются повторно используемыми только в рамках одного тестового набора (swat проекта) - и не предполагается что они будут использовать кем-то еще в других swat проектах

melezhik commented 8 years ago

Т.е. мой основной посыл наверное такой.

Проверочные файлы могут декларировать некий интерфейс для реализации ( вызов внешних проверочных утверждений ). Т.е. я себе с трудом представляю когда кто-то создает проверочный файл в котором существует вызовы внешних проверочных утверждений о которых никто не знает. Как правило, эти внешние проверочные утверждения либо УЖЕ кем-то реализованы - как cpan, perl модули ( см. мой предыдущий пример ) ввиде внешних библиотек, либо ОБЯЗАНЫ быть определены где-то еще внутри проетка и это не тайное знание, т.к. скорее всего тот же кто создает данный проверочный файл , тот же и будет реализовывать внешние проверочные утверждения.

Т.к. все происходит в рамках одного проекта и никто не собирается отдавать данный проверочный файл для повторного использвоания в другой проект ( но даже если это могло быть так - вполне валдиная ситуации очень схожая с термином интерфейс в ОО языках разработки ) - хотя в случае со сватом в этом нет необходимости ...

melezhik commented 8 years ago

Хм. Т.е. нужно вводить устное соглашение, что хук (читай - человек, пишущий хук) всегда определяет функцию с заранее оговоренным именем, или вот как выше, создает параметр типа check_f со ссылкой на функцию. А в модуле эту функцию всегда вызывать.

Собственно да. В приведенном вами примере функция вне данного модуля смысла не имеет. Она обязана быть определена, потому что ее уже где-то вызвают. Фактически это обязательный для инициализации параметр модуля.

melezhik commented 8 years ago

Я предлагаю сделать байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука

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' }
   }
)
ivanych commented 8 years ago

Тестовый сценарии обычно пишет один человек. он же определяет всевозможные внешние проверочные утвержения, которые могут быть повторно сипользованы через генераторы.

Почему один? У нас, например, несколько тестировщиков. И я хочу описать в модуле интерфейс ресурса, а тестировщики пускай дальше задают параметры и ожидаемые ответы как им заблагорассудится.

Автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API

Это бардак же. Это получается самопальное API поверх API свата. Два разработчика договорятся называть функцию check, а другие два разработчика - test, потом они поменяются местами и при написании новых тестов будут гадать, почему функция в хуке называется check, а из модуля вызывается test.

Нужна гарантия, что описанные в хуке тесты обязательно будут вызваны из модуля и не будут противоречить тестам, которые модуль вдруг сам себе как-то там сгенерирует.

Т.е. я себе с трудом представляю когда кто-то создает проверочный файл в котором существует вызовы внешних проверочных утверждений о которых никто не знает.

Да как же? Именно так всё и должно быть - модуль должен реализовать интерфейс ресурса, а параметры и результаты он проверять не должен, параметры и проверки задает совершенно другой человек, в хуке. Модуль не может знать, какие значения придут в параметрах, и модуль не может знать, какие ответы соответствуют этим параметрам.

Модуль должен просто вызвать функцию проверки из хука.

Собственно, это сейчас и происходит. Вопрос только в том, что имя этой функции сейчас предлагается оговаривать дополнительно, за рамками документации к свату. А я предлагаю задать это имя жестко, и модуль всегда должен вызывать эту функцию из вызвавшего его хука. Более того, если в хуке эта функция определена, то она должна переопределять тесты, заданные в самом модуле, чтобы не возникало конфликтов.

P.S. это всё в рамках одного проекта, я не говорю об использовании сват-модулей в других проектах.

melezhik commented 8 years ago

Почему один? У нас, например, несколько тестировщиков. И я хочу описать в модуле интерфейс ресурса, а тестировщики пускай дальше задают параметры и ожидаемые ответы как им заблагорассудится.

Вы видимо меня неправильно поняли. Архитектура swat не противоречет командой разработки кода. Просто в данном конкретном вопросе модуль не является повторно используемой единицей когда ВНЕ своего проекта. Пусть над проектом работает хоть 5 человек, но тот кто создал модуль просто напросто должен обеспечить что бы все внешние проверочные утвержения были реализованы, в частном случае - это сделает сам же автор модуля , но даже если он захочет передать "данный" модуль другим разработчикам он обязан как-то задекларировать требуемый к реализации интерфейс, устно или формально через докуменатацию это уже другой вопрос ... Не вижу с этим никаких проблем.

ivanych commented 8 years ago

Просто в данном конкретном вопросе модуль не является повторно используемой единицей когда ВНЕ своего проекта.

Это понятно.

он обязан как-то задекларировать требуемый к реализации интерфейс

Но это можно упростить и повысить надежность - просто задекларировав это на уровне самого свата.

melezhik commented 8 years ago

Это бардак же. Это получается самопальное API поверх API свата. Два разработчика договорятся называть функцию check, а другие два разработчика - test, потом они поменяются местами и при написании новых тестов будут гадать, почему функция в хуке называется check, а из модуля вызывается test.

Не очень понял утвердение про "самопальное API поверх API свата" API swat и "API" модуля две совершенно разные вещи. По поводу бардка - мой предыдущий комментарий, не очень понимаю.

Под фразой автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API - я имел ввиду именно библиотеку разработанную вне какого-то модуля. Например можно представить себе набор регэксповых выражений для валидации строк с датами, такой набор регэксп выражений можно выразить ввиде функций, используемых в проверочных файлах swat. Ни какому конкретному модулю эти функции не относятся. Вот имменно таком случае эту библиотеку безопасно сипользовать в разных swat проектах, т.к. она никоем образом не зависит от их структуры и никак не связана с конретными сват модулями. А вот связка функций ( реализующий проверочные утверждения ) для конкрентного модуля о которой я упомянул в предыдущей комметарии - совершенно другое дело - такие функции наружу в другие сват проекты никто выставлять не собиратеся

melezhik commented 8 years ago

Но это можно упростить и повысить надежность - просто задекларировав это на уровне самого свата.

Согласен. Как идея принимается. Не уверен что это легко реализовать. Но суть вашего посыла ясна. Будем подумать ...

melezhik commented 8 years ago

Да как же? Именно так всё и должно быть - модуль должен реализовать интерфейс ресурса, а параметры и результаты он проверять не должен, параметры и проверки задает совершенно другой человек, в хуке. Модуль не может знать, какие значения придут в параметрах, и модуль не может знать, какие ответы соответствуют этим параметрам.

Ок. Модуль:

melezhik commented 8 years ago

Модуль должен просто вызвать функцию проверки из хука. Собственно, это сейчас и происходит. Вопрос только в том, что имя этой функции сейчас предлагается оговаривать дополнительно, за рамками документации к свату. А я предлагаю задать это имя жестко, и модуль всегда должен вызывать эту функцию из вызвавшего его хука. Более того, если в хуке эта функция определена, то она должна переопределять тесты, заданные в самом модуле, чтобы не возникало конфликтов.

Ок. Сейчас уже больше понимания о чем вы говорите ;-) вы предлагаете сделать обязательным реализацию интерфейса модуля на стороне вызвающего кода, в данном случае хука основной истории, и валидировать выполнение этого требования средствами сват. Эта интересная идея. Я подумаю ...

ivanych commented 8 years ago

Оке, кажется, договорились:)

melezhik commented 8 years ago

Да уж :) . Но пока юзайте в таком виде. Вариантов предостаточно. Над вашей идей надо еще думать ... По первоначальной проблеме ( Несколько разных запросов к одному ресурсу ) вопросы еще есть у вас?

ivanych commented 8 years ago

Да, с исходным вопросом всё ясно, я уже сделал, работает, спасибо.

melezhik commented 8 years ago

Да, Михаил, я насчет интерфейса модулей думаю создам отдельный тикет . А мне интересно, если не секрет, какой на воде код тестов получается? можно вывести, ну по крайней мере ту часть, которую можно ))

melezhik commented 8 years ago

здесь все