是否可以在运行时跳过使用Cucumber-JVM的方案

问题描述 投票:6回答:7

我想在场景中添加一个标签@skiponchrome,这应该会在使用Chrome浏览器运行Selenium测试时跳过这个场景。这样做的原因是因为某些场景在某些环境中工作而在其他环境中不起作用,这甚至可能不是特定于浏览器测试的,并且可以应用于其他情况,例如OS平台。

示例钩子:

@Before("@skiponchrome") // this works
public void beforeScenario() {
  if(currentBrowser == 'chrome') { // this works
    // Skip scenario code here
  }
}

我知道可以在黄瓜标签中定义〜@ skiponchrome来跳过标签,但我想在运行时跳过标签。这样,当我在特定环境中开始测试运行时,我不必考虑提前跳过哪些步骤。

我想创建一个钩子来捕获标记并跳过场景而不报告失败/错误。这可能吗?

cucumber-jvm
7个回答
4
投票

我也遇到了同样的挑战,我需要在运行时动态地从应用程序中获取的标志跳过运行方案,这表明是否在应用程序上启用了要测试的功能。

所以这就是我在scenario文件中编写逻辑的方法,我们在每个步骤中都有粘合代码。

我使用了一个独特的标签'@ Feature-01AXX'来标记我的场景,只有当应用程序上有该功能(代码)时才需要运行。

所以对于每个场景,首先检查标签'@ Feature-01XX',如果它存在,则检查功能的可用性,然后才选择场景进行运行。否则它只会被跳过,而Junit不会将此标记为失败,而是将其标记为Pass。因此,如果由于功能不可用而未运行这些测试的最终结果将会通过,这很酷......

@Before
public void before(final Scenario scenario) throws Exception {
    /*
        my other pre-setup tasks for each scenario.
    */

    // get all the scenario tags from the scenario head.
    final ArrayList<String> scenarioTags = new ArrayList<>();
    scenarioTags.addAll(scenario.getSourceTagNames());

    // check if the feature is enabled on the appliance, so that the tests can be run.
    if (checkForSkipScenario(scenarioTags)) {
        throw new AssumptionViolatedException("The feature 'Feature-01AXX' is not enabled on this appliance, so skipping");
    }
}

private boolean checkForSkipScenario(final ArrayList<String> scenarioTags) {
    // I use a tag "@Feature-01AXX" on the scenarios which needs to be run when the feature is enabled on the appliance/application
    if (scenarioTags.contains("@Feature-01AXX") && !isTheFeatureEnabled()) { // if feature is not enabled, then we need to skip the scenario.
        return true;
    }
    return false;
}

private boolean isTheFeatureEnabled(){
    /*
        my logic to check if the feature is available/enabled on the application.
        in my case its an REST api call, I parse the JSON and check if the feature is enabled.
        if it is enabled return 'true', else return 'false'
    */
}

6
投票

我意识到这是对已经回答的问题的最新更新,但我想通过cucumber-jvm直接添加一个选项supported

@Before //(cucumber one)
public void setup(){
    Assume.assumeTrue(weAreInPreProductionEnvironment);
}

“如果weAreInPreProductionEnvironment为假,则情景将被标记为忽​​略(但测试将通过)。”

你需要添加

import org.junit.Assume;

与接受的答案的主要区别在于JUnit assume failures behave just like pending

重要因为bug fix你将需要cucumber-jvm版本1.2.5,在撰写本文时是最新版本。例如,以上将在cucumber-java8-1.2.3.jar中生成失败而不是pending


5
投票

我真的更喜欢通过为每个环境定义单独的运行配置来明确运行哪些测试。我还想将我使用的标签数量保持在最低限度,以保持配置数量的可管理性。

我不认为单独用标签实现你想要的东西是可能的。您需要编写一个自定义的jUnit测试运行器来代替@RunWith(Cucumber.class)。看看Cucumber实现,看看它是如何工作的。您需要根据浏览器或其他运行时条件更改RuntimeOptionsFactory创建的RuntimeOptions以包含/排除标记。

或者,您可以考虑编写一个调用测试套件的小脚本,根据您正在运行的环境构建一个动态包含/排除的标记列表。我认为这是一个更易于维护,更清晰的解决方案。


4
投票

这其实很简单。如果你挖掘Cucumber-JVM和JU​​nit 4源代码,你会发现JUnit在运行时很容易跳过(只是没有文档)。

看一下JUnit 4的ParentRunner的以下源代码,其中Cucumber-JVM的FeatureRunner(用于Cucumber,默认的Cucumber运行器):

@Override
public void run(final RunNotifier notifier) {
    EachTestNotifier testNotifier = new EachTestNotifier(notifier,
            getDescription());
    try {
        Statement statement = classBlock(notifier);
        statement.evaluate();
    } catch (AssumptionViolatedException e) {
        testNotifier.fireTestIgnored();
    } catch (StoppedByUserException e) {
        throw e;
    } catch (Throwable e) {
        testNotifier.addFailure(e);
    }
}

这就是JUnit决定显示结果的方式。如果它成功它会显示一个传递,但是在JUnit中可以使用@Ignore,那么在这种情况下会发生什么?好吧,AssumptionViolatedException(或者在这种情况下是黄瓜RunNotifier)抛出FeatureRunner

所以你的例子变成了:

@Before("@skiponchrome") // this works
public void beforeScenario() {
  if(currentBrowser == 'chrome') { // this works
    throw new AssumptionViolatedException("Not supported on Chrome")
  }
}

如果你以前使用过vanilla JUnit 4,你会记得@Ignore会在跑步者忽略测试时显示一条可选的消息。 AssumptionViolatedException带有消息,因此您应该在以这种方式跳过测试后在测试输出中看到它,而无需编写自己的自定义运行器。


1
投票

我已经实现了一个自定义的junit runner,如下所示。想法是在运行时添加标签。

因此,对于我们需要新用户的场景,我们将场景标记为“@requires_new_user”。然后,如果我们在一个环境中运行我们的测试(比如说生产环境不允许你轻易注册新用户),那么我们就会发现我们无法获得新用户。然后将“”不是@requires_new_user“添加到黄瓜选项中以跳过该场景。

这是我现在能想象的最干净的解决方案。

public class WebuiCucumberRunner extends ParentRunner<FeatureRunner> {
    private final JUnitReporter jUnitReporter;
    private final List<FeatureRunner> children = new ArrayList<FeatureRunner>();
    private final Runtime runtime;
    private final Formatter formatter;

    /**
     * Constructor called by JUnit.
     *
     * @param clazz the class with the @RunWith annotation.
     * @throws java.io.IOException                         if there is a problem
     * @throws org.junit.runners.model.InitializationError if there is another problem
     */
    public WebuiCucumberRunner(Class clazz) throws InitializationError, IOException {
        super(clazz);
        ClassLoader classLoader = clazz.getClassLoader();
        Assertions.assertNoCucumberAnnotatedMethods(clazz);

        RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(clazz);
        RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();

        addTagFiltersAsPerTestRuntimeEnvironment(runtimeOptions);

        ResourceLoader resourceLoader = new MultiLoader(classLoader);
        runtime = createRuntime(resourceLoader, classLoader, runtimeOptions);
        formatter = runtimeOptions.formatter(classLoader);
        final JUnitOptions junitOptions = new JUnitOptions(runtimeOptions.getJunitOptions());
        final List<CucumberFeature> cucumberFeatures = runtimeOptions.cucumberFeatures(resourceLoader, runtime.getEventBus());
        jUnitReporter = new JUnitReporter(runtime.getEventBus(), runtimeOptions.isStrict(), junitOptions);
        addChildren(cucumberFeatures);
    }

    private void addTagFiltersAsPerTestRuntimeEnvironment(RuntimeOptions runtimeOptions) 
    {
        String channel = Configuration.TENANT_NAME.getValue().toLowerCase();
        runtimeOptions.getTagFilters().add("@" + channel);

        if (!TestEnvironment.getEnvironment().isNewUserAvailable()) {
            runtimeOptions.getTagFilters().add("not @requires_new_user");
        }

    }
...
}

或者你可以扩展官方的Cucumber Junit测试运行器cucumber.api.junit.Cucumber和覆盖方法

    /**
     * Create the Runtime. Can be overridden to customize the runtime or backend.
     *
     * @param resourceLoader used to load resources
     * @param classLoader    used to load classes
     * @param runtimeOptions configuration
     * @return a new runtime
     * @throws InitializationError if a JUnit error occurred
     * @throws IOException         if a class or resource could not be loaded
     * @deprecated Neither the runtime nor the backend or any of the classes involved in their construction are part of
     * the public API. As such they should not be  exposed. The recommended way to observe the cucumber process is to
     * listen to events by using a plugin. For example the JSONFormatter.
     */
    @Deprecated
    protected Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader,
                                    RuntimeOptions runtimeOptions) throws InitializationError, IOException {
        ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
        return new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);
    }

您可以根据需要在此处操作runtimeOptions。但该方法被标记为已弃用,因此请谨慎使用。


0
投票

如果您正在使用Maven,您可以阅读使用浏览器配置文件,然后在那里设置相应的~exclude标签?

除非你问如何从命令行运行它,在这种情况下你用@skipchrome标记方案然后当你运行黄瓜时将黄瓜选项设置为tags = {“〜@ skipchrome”}


0
投票

如果您希望暂时跳过场景(例如,在编写场景时),可以将其注释掉(在Eclipse或Intellij中使用ctrl + /)。

© www.soinside.com 2019 - 2024. All rights reserved.