我有一个Web测试应用程序(基于Selenium,但这在这里无关紧要),它连续执行了大量的测试用例。这需要几个小时才能完成,测试用例数量会增加,所以我想使用多个Web浏览器实例并行执行多个测试用例。测试用例彼此之间没有依赖关系。
非常简化它看起来像这样:
TestExecutor executor = new TestExecutor(new FirefoxDriver());
for (TestCase test: tests) {
executor.execute(test);
// use results here
}
现在我不确切知道如何并行化这个。我可以轻松地创建几个连接到多个Web浏览器的TestExecutor作为Callables并使用Executors,CompletitionServices和其他好帮手类,但我该怎么做:
使用之前的TestCase准备好后,将新的TestCase传递给TestExecutor? Callable中的call()方法不带参数,所以我可能必须在我的TestExecutor类中实现一些setNextTestCase()来实现这一点,我发现它并不是很好。还有更好的选择吗?
重用TestExecutor实例来执行下一个测试用例?由于每个TestExecutor实例都需要一个Web浏览器实例,因此如果我为每个测试用例创建一个新的TestExecutor,则需要很长时间来初始化它并导致许多窗口在屏幕上闪烁。
答案 0 :(得分:5)
在使用之前的TestCase准备好后,将新的TestCase传递给TestExecutor?
如果我理解你,这是一个常见的问题。线程池中有许多线程,但每个线程都有一些上下文 - 在本例中是“Web浏览器”。您不希望为提交给线程池的每个作业启动新的浏览器。
以下是有关如何实现此目标的一些想法。
拥有BlockingQueue
个TestCase
个对象。然后,每个线程初始化其浏览器,然后从TestCase
对象队列中出队,直到队列为空或某些shutdown boolean设置为true。您可以将TestExecutor
个对象提交到线程池中,但是它们会通过您自己的队列自行将TestCase
个对象出列。您不将TestCase
提交给线程池。
BlockingQueue<TestCase> testCaseQueue = new LinkedBlockingQueue<>();
for (TestCase test: tests) {
testCaseQueue.add(test);
}
// now make your executors and run them in a thread-pool
TestExecutor testExecutor =
new TestExecutor(new FirefoxDriver(), testCaseQueue);
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.submit(testExecutor);
...
// once you've submitted your last executor, you shutdown the pool
threadPool.shutdown();
...
// inside of the executor, they dequeue tests from `testCaseQueue`
while (!shutdown) {
TestCase testCase = testCaseQueue.poll(0, TimeUnit.MILLISECONDS);
if (testCase == null) {
break;
}
...
}
另一个想法是将TestCase
提交给线程池并使用ThreadLocal
来获取之前配置的测试浏览器。这不是最佳选择,因为在测试完成后很难适当地终止浏览器。
答案 1 :(得分:0)
我建议设置一个Queue
/ List
TestExecutors
。然后创建一个包裹Callable
的{{1}} / Runnable
。您TestCase
的{{1}}与[{1}} ExecutorService
的线程数相同。 List
的第一步是从TestExecutors
检索/弹出Runnable
。它会利用执行程序进行测试,然后在完成时将其放回队列中。