Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I run my independent Robotium UI tests in parallel?

I'm using Jenkins for my Android continuous integration. I have some isolated, independent Robotium UI tests that currently take 12 minutes to run serially against a single emulator. Can anybody recommend a good way to run them in parallel so it will take only 6 minutes (or less)?

I know about various ways to run the full test suite in parallel on multiple devices/emulators, e.g. see the Multi-configuration (matrix) job section of the Jenkins Android Emulator Plugin, Spoon, or cloud testing companies like AppThwack.

I know how to run a specific subset of my tests, by using JUnit annotations, or apparently Spoon supports a similar function (see my question about it).

I'm now using Spoon to run my full test suite (mostly to take advantage of the lovely HTML output with screenshots). If anybody has tips on the best way to split my tests and run them in parallel, that would be great.

I assume I could achieve this by splitting the tests into two separate CI jobs, but it sounds like a pain to maintain two separate jobs and combine the results.

like image 948
Dan J Avatar asked Jul 20 '14 00:07

Dan J


2 Answers

Update: I've added another answer which I think gives a cleaner and more concise Jenkins configuration, and is based more directly on Spoon.


I've just discovered the Jenkins MultiJob Plugin which allows you to run multiple jobs in parallel within a Phase.

Below is my working, but slightly fragile approach to doing this using the Fork plugin. I use manually configured regular expressions to partition the tests (this was the main reason I tried to use Fork - it supports using regex).

The MultiJob looks like this with multiple downstream jobs in a Phase:

multi_job_summary

Main job configuration

Here's how my "Android Multi Job" is configured:

multi_job_summary_1multi_job_summary_2

Downstream job configuration

Here's how the downstream "Android Phase N" jobs are configured (with different android.test.classes regular expressions for each):

downstream_config

Gotchas

  • Fork currently fails to run on Gradle v1.0.0, as per fork plugin issue #6.
  • If you want a Fork regex to match multiple different packages, you need to comma separate your regex. This isn't very well documented in the Fork project, but their TestClassFilter source shows you how they interpret the regex.
  • Any abstract test classes need to be named Abstract*, otherwise Fork will try to run them as tests, creating annoying failures. Their TestClassScanner controls this, and issue #5 tracks changing this.
  • IIRC, you need to have the Fingerprint Plugin installed for the "Aggregate downstream test results" option to work. If you don't have it installed you'll see this error: "Fingerprinting not enabled on this build. Test aggregation requires fingerprinting."

Limitations

  • Test results are aggregated, but only using the JUnit XML test reports. This means you need to click through to each downstream job to view nice HTML results.
  • Manually partitioning your tests based on regular expressions can be tedious and error prone. If you use this approach I recommend you still have a nightly/weekly Jenkins job to run your full test suite in a single place, to make sure you don't accidentally lose any tests.
  • This MultiJob approach requires you to manually configure each downstream job, one for each slave node you want to use. We've prototyped a better approach using a Matrix job, where you only have to configure everything in a single Jenkins job). We'll try to write that up in the next couple of weeks.

Futures

We've also prototyped a way of extending Spoon (the output is more pretty than Fork) to automatically split the whole test suite across N downstream jobs. We still need to enhance it to aggregrate all those results back into a single HTML page in the upstream job, but unfortunately a bug in the Jenkins "Copy To Slave" plugin is blocking this from working at the moment.

like image 152
Dan J Avatar answered Oct 05 '22 23:10

Dan J


You can perform this in 3 steps:

  1. Create 2 nodes pointing to the single target machine (which satisfies your condition to run tests on same machine).
  2. In the Job during execution use the Jenkins env variable $NODE_NAME to and assign different set of tests to each node (you may need the NodeLabel Parameter Plugin).
  3. After execution you will have 2 report files, luckily on the same machine. You can either merge them into one if they are text files or create xml something similar to PerfPublisher plugin format which gives you detailed report.

It means you can actually execute 2 sets of tests on same machine (2 nodes pointing to it) using a single job. Obtaining single report would be tricky but If I get to know the format I can help.

Hope this is useful

like image 40
Waman Avatar answered Oct 06 '22 00:10

Waman