首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Cucumber-jvm线程安全吗?

Cucumber-jvm线程安全吗?
EN

Stack Overflow用户
提问于 2014-07-29 06:00:14
回答 4查看 4.3K关注 0票数 7

我想在多个线程中运行相同的Cucumber测试。更具体地说,我有一组特性,在一个线程中运行这些特性效果很好。我使用JSON格式化程序记录每个步骤的运行时间。现在我想做负载测试。我更关心多线程环境中每个特性/步骤的运行时间。因此,我创建了多个线程,每个线程运行在相同的功能集上。每个线程都有自己的JSON报告。这在理论上是可能的吗?

由于某些项目设置的原因,我不能使用JUnit运行器。所以我不得不求助于CLI-way:

代码语言:javascript
复制
        long threadId = Thread.currentThread().getId();
        String jsonFilename = String.format("json:run/cucumber%d.json", threadId);

            String argv[] = new String[]{
                "--glue",
                "com.some.package",
                "--format",
                jsonFilename,
                "d:\\features"};

        // Do not call Main.run() directly. It has a System.exit() call at the end.             
        // Main.run(argv, Thread.currentThread().getContextClassLoader());

        // Copied the same code from Main.run(). 
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        RuntimeOptions runtimeOptions = new RuntimeOptions(new Env("cucumber-jvm"), argv);
        ResourceLoader resourceLoader = new MultiLoader(classLoader);
        ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
        Runtime runtime = new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);
        runtime.writeStepdefsJson();
        runtime.run();      

我尝试为每个Cucumber运行创建一个单独的线程。问题是,只有一个线程具有有效的JSON报告。所有其他线程只创建空的JSON文件。这是Cucumber设计出来的,还是我漏掉了什么?

EN

回答 4

Stack Overflow用户

发布于 2016-04-13 10:51:01

我们使用优秀的GPars library研究了Gradle和Groovy下的多线程黄瓜测试。我们有650个UI测试,而且还在不断增加。

在多线程中运行cucumber-JVM时,我们没有遇到任何明显的问题,但是多线程也没有像我们希望的那样提高性能。

我们在单独的线程中运行每个功能文件。有一些细节需要注意,比如将来自不同线程的cucumber报告拼接在一起,并确保我们的步骤代码是线程安全的。我们有时需要在两个步骤之间存储值,因此我们使用与线程id相关的concurrentHashMap来存储这种数据:

代码语言:javascript
复制
class ThreadedStorage {
    static private ConcurrentHashMap multiThreadedStorage = [:]

    static private String threadSafeKey(unThreadSafeKey) {
        def threadId = Thread.currentThread().toString()
        "$threadId:$unThreadSafeKey"
    }

    static private void threadSafeStore(key, value) {
        multiThreadedStorage[threadSafeKey(key)] = value
    }

    def static private threadSafeRetrieve(key) {
        multiThreadedStorage[threadSafeKey(key)]
    }


}

下面是使用GPars多线程运行测试的Gradle任务代码的要点:

代码语言:javascript
复制
def group = new DefaultPGroup(maxSimultaneousThreads())
def workUnits = features.collect { File featureFile ->
    group.task {
        try {
            javaexec {
                main = "cucumber.api.cli.Main"
                ...
                args = [
                     ...
                     '--plugin', "json:$unitReportDir/${featureFile.name}.json",
                             ...
                             '--glue', 'src/test/groovy/steps',
                             "path/to/$featureFile"
                    ]
            }
        } catch (ExecException e) {
                ++noOfErrors
                stackTraces << [featureFile, e.getStackTrace()]
        }
    }
}
// ensure all tests have run before reporting and finishing gradle task
workUnits*.join()

我们发现我们需要以与执行时间相反的顺序呈现功能文件,以获得最佳结果。

结果是在i5处理器上提高了30%,降低了4个以上的并发线程,这有点令人失望。

我认为线程对于我们的硬件上的多线程来说太重了。在一定数量的线程之上,有太多的CPU缓存未命中。

使用像Amazon SQS这样的线程安全的工作队列在不同的实例上并发运行现在看起来是一个很好的前进方向,特别是因为它不会受到线程安全问题的影响(至少在测试框架方面不会)。

对于我们来说,由于工作场所的安全限制,在i7硬件上测试这种多线程方法并不是一件容易的事情,但我非常有兴趣了解一下具有更大CPU缓存和更多物理内核的i7的比较结果。

票数 2
EN

Stack Overflow用户

发布于 2015-04-15 13:42:11

当前不是--这是您观察到的the issue。我还没有找到任何按场景并行化的方法。

这是一个很好的关于穷人并发的write up。只需运行多个命令,每个命令选择不同的测试子集--按功能或标记。我会派生一个新的虚拟机(就像JUnit驱动程序那样),而不是尝试将其线程化,因为cucumber不是为此而设计的。你必须自己权衡它们,然后弄清楚如何组合这些报告。(但至少问题是合并报告,而不是腐败的报告。)

票数 1
EN

Stack Overflow用户

发布于 2016-11-10 04:16:41

假设您可以使用下面的Maven POM配置并行运行您的Cucumber-JVM测试:https://opencredo.com/running-cucumber-jvm-tests-in-parallel/

代码语言:javascript
复制
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.14</version>
    <executions>
        <execution>
            <id>acceptance-test</id>
            <phase>integration-test</phase>
            <goals>
                <goal>test</goal>
            </goals>
            <configuration>
                <forkCount>${surefire.fork.count}</forkCount>
                <refuseForks>false</reuseForks>
                <argLine>-Duser.language=en</argLine>
                <argLine>-Xmx1024m</argLine>
                <argLine>-XX:MaxPermSize=256m</argLine>
                <argLine>-Dfile.encoding=UTF-8</argLine>
                <useFile>false</useFile>
                <includes>
                    <include>**/*AT.class</include>
                </includes>
                <testFailureIgnore>true</testFailureIgnore>
            </configuration>
        </execution>
    </executions>
</plugin>

在上面的代码片段中,您可以看到maven-surefire-plugin用于运行我们的验收测试--任何以*AT结尾的类都将作为JUnit测试类运行。多亏了JUnit,现在只需设置forkCount配置选项,就可以使测试并行运行。在示例项目中,它被设置为5,这意味着我们一次最多可以运行5个线程(即5个runner类)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25005057

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档