Cześć,
mam w Behat3 taki scenariusz:
Scenario: Get task
Given Entity "task" exists:
| property | value |
| title | Hello |
| description | Lorem ipsum dolor sit amet |
When I send a GET request with placeholder to "/api/task/{{task.id}}.json"
And the JSON should match pattern:
"""
{
"title: "Hello",
"description: "Lorem ipsum dolor sit amet",
"id": "%integer"
}
"""
Tak naprawdę każdy z tych stepów jest w innym Context.
Entity :entityName exists w DataContext
I send a :method request w ApiContext
the JSON should match pattern w MatcherContext
W DataContext mam coś w stylu:
$this->entities[$entityName] = new $entityName();
W MatcherContext mam coś w stylu:
$current = $this->getSession()->getPage()->getContent(); // (możliwe bo ApiContext korzysta z RawMinkContext)
$matcher->match($current, $expected);
W ApiContext chciałbym mieć coś w stylu:
$url = $this->applyPlaceholder($url);
$this->sendRequest($url);
Problem w tym, że applyPlaceholder jest zależne od tego co do tej bazy już dodałem ($this->entities z DataContext).
Rozwiązanie 1 jakie pierwsze mi przyszło do głowy, to: DataContext zamienić na FeatureContext, I w nim użyć Step Execution Chaining:
return new When("I send request a ....");
Ale w Behat3 nie ma już Chainingu w Core, ChainedStepsExtension wydaje się nie działać (chyba, że ktoś ma inne dane).
Rozwiązanie 2: W DataContext i ApiContext użyć traita Behat\Symfony2Extension\Context\KernelDictionary; W DataContext ->setParameter('entity_holder', $this->entities); W ApiContext ->getParameter('entity_holder');
Tak, to wiąże mi Behata z Symfony2Extension na stałe. Byłbym w stanie to jeszcze jakość znieść, bo *.features, i tak są w Symfony, i tak korzystają gdzieś tam z tego Extension. Ale container jest już zamrożony:
Impossible to call set() on a frozen ParameterBag. (Symfony\Component\DependencyInjection\Exception\LogicException)
Rozwiązanie 3: W tej chwili ApiContext dziedziczy, rozszerza Sanpi\Behatch\Context\RestContext (udostępnia wysyłanie tego requesta, rozszerzam go o możliwość podania placeholdera). Więc mógłbym po tym dziedziczyć w DataContext, a ApiContext po DataContext, ale to rozwiązanie które wydaje mi się najbrzydsze z możliwych.
W sumie problem powinien być dość popularny, a jednak nie potrafię znaleźć dobrego rozwiązania. Czy ktoś miałby pomysł jak można rozwiązać ten problem?
PS. Nawet jeśli wydaje Ci się, że masz głupi pomysł, to podrzuć - być może będzie on lepszy niż pozostałe.
Najlepszym rozwiązaniem byłoby podpiąć się pod event
@BeforeStep
i w nim zmodyfikować wartości wStepNode
, niestety jest to niemożliwe gdyżStepNode
nie ma setterów.Rozwiązanie 1
Stworzenie
ParameterBag
i wstrzykiwanie go do klasContext
które implementują TwójParameterBagContextAware
.Spójrz na Behat/WebApiExtension tam jest to zrealizowane (klasy
Extension
,Initializer
).Rozwiązanie 2
Stworzenie
Extension
wstrzykującego nowegoEventDistpatcher
, który będzie przede wszystkim niezależny od dispatchera z Behata (który to jest lekko zmodyfikowany).I używanie eventów do celów aktualizacji np. Twoich url.
Oczywiście placeholdery w
ApiContext
powinny być aktualizowane tylko w ramach danego Scenariusza, więc musisz sam to sobie rozwiązać.PS. Możesz też zrobić eventy zrobić na odwrót, że to
ApiContext
będzie listenerem.