【问题标题】:Concurrent JUnit Tests with Parameters带参数的并发 JUnit 测试
【发布时间】:2012-04-13 13:23:08
【问题描述】:

所以我正在尝试运行并行参数化测试。我有一个解决方案,其中相同的测试可以与提供的参数并行运行,例如说我有以下内容:

@Test
public void someTest1(){
}

@Test
public void someTest2(){
}

我可以让 someTest1() 使用所有参数同时运行,但是 someTest2() 仍然必须等待 someTest1() 在执行之前完成所有参数。我想知道是否有人知道能够同时运行带有所有参数的 someTest1() 和带有所有参数的 someTest2() 的解决方案?我试过tempus-fugit concurrent test runner,它非常适合未参数化的测试...

下面是我当前并行运行每个参数测试的代码。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.junit.runners.Parameterized;
import org.junit.runners.model.RunnerScheduler;

/**
 * Class used from the following source:
 * http://jankesterblog.blogspot.com/2011/10
 * /junit4-running-parallel-junit-classes.html
 * 
 * @author Jan Kester
 * 
 */
public class Parallelized extends Parameterized {

    private static class ThreadPoolScheduler implements RunnerScheduler {
        private ExecutorService executor;

        public ThreadPoolScheduler() {
            String threads = System.getProperty("junit.parallel.threads", "16");
            int numThreads = Integer.parseInt(threads);
            executor = Executors.newFixedThreadPool(numThreads);
        }

        public void finished() {
            executor.shutdown();
            try {
                executor.awaitTermination(12, TimeUnit.HOURS);
            } catch (InterruptedException exc) {
                throw new RuntimeException(exc);
            }
        }

        public void schedule(Runnable childStatement) {
            executor.submit(childStatement);
        }
    }

    /**
     * Instantiates a new parallelized.
     * 
     * @param klass
     *            the klass
     * @throws Throwable
     *             the throwable
     */
    public Parallelized(Class<?> klass) throws Throwable {
        super(klass);
        setScheduler(new ThreadPoolScheduler());
    }
}

下面的代码是一个示例测试,BaseSuite 不包含任何重要的内容。这些与 selenium 一起使用,因此它只设置 webDriver。 getAllButOpera() 方法返回包含 Internet Explorer、Firefox 和 Chrome 的浏览器类型的集合。这些参数用于在firefox ie 和chrome 上同时运行相同的测试。我想在课堂上同时运行这两个测试,这是我遇到的问题。

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Collection;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.openqa.selenium.WebDriver;


/**
 * The Class SampleSuite1.
 * 
 * @author Reid McPherson
 */
@RunWith(Parallelized.class)
public class SampleSuite1 {
    WebDriver driver;
    /**
     * Data.
     * 
     * @return the collection
     */
    @Parameters
    public static Collection<Object[]> data(){
          List<Object[]> browsers = new ArrayList<Object[]>();
    browsers.add(new String[]{"Firefox"});
    browsers.add(new String[]{"Chrome"});
    browsers.add(new String[]{"IE"});
    return browsers;
    }

    /**
     * Instantiates a new sample suite1.
     * 
     * @param type
     *            the type
     */
    public SampleSuite1(String type){
        switch (type) {
    case "FIREFOX":
        driver = new FirefoxDriver();
        break;
    case "IE":
        driver = new InternetExplorerDriver();
        break;
    case "CHROME":
        System.setProperty("webdriver.chrome.driver", PATHTOCHROMEEXE);
        driver = new ChromeDriver();
        break;
    case "OPERA":
        driver = new OperaDriver();
        break;
    default:
        throw new RuntimeException("Browser type unsupported");
    }
    // Set the timeout.
    driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
    }

    /**
     * Sets the up.
     */
    @Before
    public void setUp() {
        driver.get("http://www.google.com");
    }

    /**
     * Test navigation succeeded.
     */
    @Test
    @TestDescription("Navigation Test")
    public void navigationShouldSucceed() {
        String pageSource = driver.getPageSource();
        assertTrue(pageSource.contains("Google"));
    }

    /**
     * Test title.
     */
    @Test
    @TestDescription("This method tests the web page title.")
    public void titleShouldBeGoogle() {
        assertEquals(driver.getTitle(), "Google");
    }

    @After
    public void finished(){
    driver.close();
    }


}

【问题讨论】:

  • 我不想在这里获得答案,但这不是测试并发代码的正确方法。如果您想学习如何做到这一点,我可能会向您指出“Java 并发实践”一书的相关部分。
  • 我正在测试的代码不是并发的,我只想同时运行测试。
  • 好吧,也许我在这里误解了您的意图:我假设您询问如何同时运行测试的原因是因为您需要测试代码的并发行为。
  • 那么问题可能不是JUnit本身,而是Webdriver。看看如何配置它以在多个实例中运行。
  • 我的目标是在不同的浏览器上测试一个网站,而不必为每个浏览器重写测试。目前它们是否同时发生对我来说并不重要。

标签: java concurrency selenium junit parallel-processing


【解决方案1】:

正如我所说,问题在于 JUnit 的实现。

你可以看到:

Parallelized extends Parametrized extends Suite extends ParentRunner

另一方面:

ConcurrentTestRunner extends BlockJUnit4ClassRunner extends ParentRunner

因此它们来自不同的继承层次。

现在你要看看的是:

org.junit.runners.ParentRunner#getChildren

方法。对于 org.junit.runners.BlockJUnit4ClassRunner 它是:

protected List<FrameworkMethod> computeTestMethods() {
    return getTestClass().getAnnotatedMethods(Test.class);
}

生成所有带有注释的方法。但是对于 org.junit.runners.Parameterized 它是:

for (int i= 0; i < parametersList.size(); i++)
  runners.add(newtestClassRunnerForParameters(getTestClass().getJavaClass(),
                parametersList, i));

最后一个只给出类。

建议:用org.junit.runners.ParentRunner#getChildren from BlockJUnit4ClassRunner 的定义覆盖您的并行化类。

【讨论】:

  • 我有点困惑。那么我不应该在Parallelized 类中扩展Parameterized 吗?如何将List&lt;FrameworkMethod&gt; 转换为List&lt;Runner&gt;
  • 是的。我已经看到了。我尝试使用 BlockJUnit4ClassRunner 的跑步者,但它不兼容。如果您将使用 org.junit.experimental.ParallelComputer 和 org.junit.experimental.theories.ParametersSuppliedBy 会怎样? ParallelComputer 为您提供并行执行,因此您可以删除 Parallelized。并且 ParametersSuppliedBy 可用于生成数据,如 public static Collection data() ,然后您可以为每个测试方法创建一个驱动程序。覆盖解决方案将是一个非常大的黑客,恕我直言会有些尴尬。
  • 我已经尝试过ParallelComputer,但是如果我使用ParallelComputer,结果将不再通过框架报告。
  • 好的。我认为有一个非常简单但不优雅的解决方案:您可以为每个测试方法创建一个测试类。
  • 是的,这可行,但在我的工作中必须组织测试的方式并不能使其成为可行的解决方案。顺便说一句,感谢您的帮助。
【解决方案2】:

感谢您的帮助,除了运行并发套件之外,我最终使用了来自 here 的代码,它使我能够同时运行测试,但它不会同时运行相同的测试。

【讨论】:

  • 从未想过切换到TestNG?
  • 是的,我有。我用过TestNG,我喜欢它。我被告知不要使用 TestNG,因为他们不想拥有竞争库,也不想重写测试以与 TestNG 兼容(即使 TestNG 使这很容易做到)。这个决定不是由我决定的,但我确实为它而战,哈哈。
【解决方案3】:

我也在使用 Jeeunit 的代码...但是即使是 1.0 版本也有错误。

ConcurrentRunnerScheduler中必须实现finished方法。

所以我只是把代码拉出来,像 suiteFinished() 方法一样实现:

@Override
    public void finished() {
        try {
        while (!tasks.isEmpty())
            tasks.remove(completionService.take());
    }
    catch (InterruptedException e) {
        System.out.println("suite fin");
        Thread.currentThread().interrupt();
    }
    finally {
        while (!tasks.isEmpty())
            tasks.poll().cancel(true);
        executorService.shutdownNow();
    }

}

【讨论】:

    【解决方案4】:

    这是我尝试过的,对我来说效果很好。

    public class ParallelTests {
       static ExecutorService eService ;
       public static void main(String[] args) {
          testA() ;
          testB() ;
          testC() ;
       }
       public static void testA() {
          eService = Executors.newCachedThreadPool() ;
          for (int i = 0 ; i < 10 ; i++) {
             TestA testA = new TestA() ;
             eService.execute(testA) ;
          }
          eService.shutdown() ;
          while(!eService.isShutDown()) {
          }
       }
    //same for testB and testC
    }
    
    public class TestA implements Runnable {
        public TestA() {
        }
        @Test
        public myTest throws Throwable {
        }
    }
    

    【讨论】:

    • 你在签名中有一个错误:$ public myTest throws Throwable { $ 所以它甚至不会编译。另外,它不再是 JUnit - 他也不能使用 JUnit 报告。
    • 它仍然存在 :) myTest 是方法名还是返回值或两者兼而有之?
    猜你喜欢
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2019-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-19
    相关资源
    最近更新 更多