Pregunta

I have an application for web testing (based on Selenium but this should not matter much here) which executes quite a number of test cases successively. It takes a couple of hours to complete and the number of test cases grows so I would like to use multiple web browser instances to execute several test cases in parallel. The test cases have no dependency on each other.

Very simplified it looks like this:

TestExecutor executor = new TestExecutor(new FirefoxDriver());
for (TestCase test: tests) {
    executor.execute(test);
    // use results here
}

Now I do not know exactly how to parallelize this. I can easily create several TestExecutors connected to several web browsers as Callables and use Executors, CompletitionServices and other nice helper classes but how do I:

  • pass a new TestCase to a TestExecutor once it is ready with the previous TestCase? The call() method in Callable takes no arguments, so I probably have to implement some setNextTestCase() in my TestExecutor class to achieve this which I don't find really nice. Are there any better alternatives?

  • reuse the TestExecutor instance for the execution of the next test case? Since every TestExecutor instance requires a web browser instance it takes a long time to initialize it and would result in many windows flashing on the screen if I would create a new TestExecutor for every test case.

¿Fue útil?

Solución

pass a new TestCase to a TestExecutor once it is ready with the previous TestCase?

This is a common question if I'm understanding you. You have a number of threads in a thread-pool but each thread has some context -- in this case a "web browser". You don't want to have to start up a new browser for every job submitted to the thread-pool.

Here are some ideas about how to accomplish this.

  • Have a BlockingQueue of TestCase objects. Each of your threads then initialize their browser and then dequeue from the queue of TestCase objects until the queue is empty or some shutdown boolean is set to true. You could the submit your TestExecutor objects into a thread-pool, but they would do their own dequeuing of the TestCase objects though your own queue. You would not submit the TestCase to the thread-pool.

    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;
        }
        ...
    } 
    
  • Another idea would be to submit the TestCase to the thread pool and use a ThreadLocal to get the previously configured browser for the test. This is not as optimal because it makes it hard to terminate the browser appropriately when the tests have completed.

Otros consejos

I would recommend setting up a Queue / List of TestExecutors. Then create a Callable / Runnable that wraps the TestCase. You ExecutorService would have the same number of threads as your List of TestExecutors. The first step of the Runnable would be to retrieve / pop a TestExecutor from the Queue. It would utilize the executor for the test then when done put it back in the queue.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top