Расширение контекстов Symfony2 Behat приведет к тому, что шаг уже определен

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

behat.yml

suites:
    common:
        type: symfony_bundle
        bundle: CommonBundle
        mink_session: symfony2
        mink_javascript_session: selenium2
        autoload:
            'CommonContext': %paths.base%/src/xxx/CommonBundle/Features/Context
        contexts: [ xxx\CommonBundle\Features\Context\CoreContext ]

    user:
        type: symfony_bundle
        bundle: UserBundle
        mink_session: symfony2
        mink_javascript_session: selenium2
        autoload:
            'UserContext': %paths.base%/src/xxx/UserBundle/Features/Context
        contexts:
            - Behat\MinkExtension\Context\MinkContext
            - xxx\CommonBundle\Features\Context\CoreContext
            - xxx\UserBundle\Features\Context\UserContext

DefaultContext.php

namespace XXX\CommonBundle\Features\Context;

use ...

/**
 * Class DefaultContext
 */
class DefaultContext extends MinkContext implements Context, KernelAwareContext
{

    /**
     * @param AbstractEntity $oEntity
     *
     * @return object
     */
    protected function getRepository(AbstractEntity $oEntity)
    {
        return $this->getService($oEntity);
    }

    /**
     * @return mixed
     */
    protected function getEntityManager()
    {
        return $this->getService('doctrine')->getManager();
    }

    /**
     * @param $id
     *
     * @return object
     */
    protected function getService($id)
    {
        return $this->getContainer()->get($id);
    }

CoreContext.php

namespace XXX\CommonBundle\Features\Context;

use ...

/**
 * Class SubContext
 */
class CoreContext extends DefaultContext implements Context, SnippetAcceptingContext
{

    /**
     * @Given I visit the homepage
     * @When I visit the homepage
     */
    public function iVisitHomepage()
    {
        $this->visitPath('/');
    }

    /**
     * @And /^I am logged in as "([^"]*)"$/
     * @Then /^I am logged in as "([^"]*)"$/
     */
    public function iAmLoggedInAs($username)
    {
        $user = $this->getContainer()->get('fos_user.user_manager')->findUserByUsername($username);

        $this->visit('/login');

        $this->fillField('_username', $user->getEmailCanonical());
        $this->fillField('_password', self::USER_PASSWORD);

        $this->pressButton('_submit');
    }

UserContext.php

namespace xxx\UserBundle\Features\Context;

use ...

/**
 * Defines application features from the specific context.
 */
class UserContext extends CoreContext implements Context, SnippetAcceptingContext
{

    /**
     * Initializes context.
     *
     * Every scenario gets its own context instance.
     * You can also pass arbitrary arguments to the
     * context constructor through behat.yml.
     */
    public function __construct()
    {
    }

}

register_user.feature

Feature: Register user

  @javascript
  Scenario: Register user
    Given I am on homepage
    And I go to "/register/"
    And I am logged in as "[email protected]"
    Then I should see "Terms and Conditions"

Итак, когда я запускаю тест, я получаю сообщение об ошибке:

Given I am on homepage
      Step "I visit the homepage" is already defined in xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()

      xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
      xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
    And I go to "/register/"
      Step "I visit the homepage" is already defined in xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()

      xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()
      xxx\CommonBundle\Features\Context\CoreContext::iVisitHomepage()

Я понял это совершенно неправильно или мне не хватает некоторых настроек здесь?


person Herr Nentu'    schedule 14.02.2016    source источник


Ответы (2)


Не расширяйте контексты, содержащие определения шагов. Обойти это невозможно.

Хорошие расширения предоставляют контексты с удобными методами, но без определения шагов. В случае расширения Mink рядом с MinkContext у вас также есть RawMinkContext. Первый содержит определения шагов и не должен расширяться. Другой предоставляет вспомогательные методы, которые могут вас заинтересовать. RawMinkContext — это тот, который вы должны расширить. В качестве альтернативы вы также можете использовать файл MinkAwareTrait.

person Jakub Zalas    schedule 14.02.2016
comment
Хорошо, но если я использую больше контекстов в качестве массива внутри behat.yml, он все равно возвращает ту же ошибку. Если вы видите, что я сделал в пользовательском наборе. Это имеет отношение к той же логике? - person Herr Nentu'; 14.02.2016
comment
Вы не получите ошибку, если не включите один и тот же контекст несколько раз или один из ваших контекстов не расширит контекст, содержащий шаги. Оба ваших контекста расширяют CoreContext, который расширяет MinkContext (через DefaultContext). MinkContext содержит определения шагов и НЕ ДОЛЖЕН быть расширен. - person Jakub Zalas; 15.02.2016
comment
По моему опыту, стоит сохранять уровни наследования простыми, и я вряд ли буду расширять другие контексты. Вспомогательные методы, такие как ваш getRepository(), могут быть включены в трейты. - person Jakub Zalas; 15.02.2016
comment
Да, вы правы с чертами. Я думаю, то, что вы говорите, имеет смысл. Попробую. Надеюсь, это работает! - person Herr Nentu'; 15.02.2016

Произошел сдвиг в том, какие контексты находятся в Behat2 и какие они теперь в Behat3. Контексты в Behat3 больше связаны с «ситуациями», в которых могут возникнуть ваши тесты. Например:

  • Вы вошли
  • Анонимный посетитель
  • Вызов общедоступного API
  • Аутентифицированный вызов API
  • Браузер с отключенным javascript
  • Включенный javascript браузер

И так далее.

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

Надеюсь, поможет

person hasumedic    schedule 14.02.2016