9

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

示例钩子:

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

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

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

4

7 回答 7

8

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

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

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

您将需要添加

import org.junit.Assume;

与已接受答案的主要区别在于JUnit 假设失败的行为就像挂起

重要由于一个错误修复,您将需要 cucumber-jvm 版本 1.2.5,在撰写本文时它是最新的。例如,上面会在 cucumber-java8-1.2.3.jar 中生成失败而不是挂起

于 2016-12-09T16:56:16.790 回答
5

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

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

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

于 2013-04-23T18:49:26.397 回答
5

这真的很容易。如果您深入研究 Cucumber-JVM 和 JUnit 4 源代码,您会发现 JUnit 使得在运行时跳过非常容易(只是未记录)。

查看以下 JUnit 4 的源代码ParentRunner,其中 Cucumber-JVM 的FeatureRunnerCucumber在默认 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 决定显示什么结果的方式。如果成功,它将显示通过,但@Ignore在 JUnit 中是可能的,那么在这种情况下会发生什么?好吧, an是由(或在本例中为Cucumber )AssumptionViolatedException抛出的。RunNotifierFeatureRunner

所以你的例子变成:

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

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

于 2015-11-20T19:20:01.687 回答
4

我也遇到了同样的挑战,我需要根据我在运行时从应用程序动态获取的标志跳过运行场景,该标志告诉应用程序是否启用了要测试的功能。

所以这就是我在场景文件中编写逻辑的方式,每个步骤都有胶水代码。

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

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

@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'
    */
}
于 2016-11-30T11:32:12.130 回答
1

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

所以说对于我们需要新用户的场景,我们将场景标记为“@requires_new_user”。然后,如果我们在一个环境中运行我们的测试(比如不允许您轻松注册新用户的生产环境),那么我们会发现我们无法获得新用户。然后将 ""not @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。但是该方法被标记为已弃用,因此请谨慎使用。

于 2019-03-05T22:47:46.833 回答
0

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

除非您询问如何从命令行运行它,在这种情况下,您使用 @skipchrome 标记场景,然后在运行 cucumber 时将 cucumber 选项设置为 tags = {"~@skipchrome"}

于 2013-04-16T21:25:55.180 回答
0

如果您只想暂时跳过一个场景(例如,在编写场景时),您可以将其注释掉(在 Eclipse 或 Intellij 中是ctrl+ )。/

于 2019-02-20T14:22:48.890 回答