Jenkins Integration Testing for Plugin Development
This article describes how to use a Jenkins continuous integration server for automating PHPUnit and Behat tests for Moodle and Moodle plugins. The configuration uses Moodle's way of running PHPUnit and Behat tests using the command line.
Integration scenario: We are developing a Moodle plugin. We want to run automated tests, ensuring that it runs correctly on multiple Moodle platform versions, e.g., Moodle 2.7 and Moodle 2.8. This is motivated by the fact that we announce compatibility with these versions in the Moodle plugin directory, and we want to - at least - know, when a plugin becomes incompatible with an older version or needs to be changed. Since we are only running one recent Moodle version for development, automated tests with other versions are useful for us.
Prerequisites for this manual: Ubuntu-based integration server, headless (i.e. without a graphical environment), here: Ubuntu 14.04.
Installation of required software
- Install Jenkins as a Ubuntu native package, as described on their website (instructions currently at http://pkg.jenkins-ci.org/debian/).
- Install a Moodle runtime environment. A web server is not needed, since PHP 5's standalone server will be used. The following commands were used for our system:
sudo apt-get install postgresql<br />
sudo apt-get install php5-cli php-pear php5-curl php5-pgsql php5-gd php5-intl
- Install git, which will be used to obtain the sources of Moodle and of your plugin.
sudo apt-get install git
- For acceptance tests, you need to use a browser. Therefore you need to be able to run graphical applications. On headless servers (i.e. those without a display), you can install Xvfb, emulating a display which will be used by your browser.
sudo apt-get install xvfb firefox
- Furthermore, acceptance tests require the Selenium standalone server to be installed. Download from http://www.seleniumhq.org/download/ (here: Version 2.45.0) and unpack it at a jenkins-accessible location, e.g. $JENKINS_HOME/selenium (here: /var/lib/jenkins/selenium).
Basic configuration of Jenkins using the shell
- Configuration of the init script can be found at . It is not strictly necessary to change anything here, but we set
/etc/default/jenkins
and addedHTTP_PORT=-1
to make the server only via HTTPS. In that case, you also need to addHTTPS_PORT=8998
to the--httpsPort=$HTTPS_PORT
variable and restart Jenkins.JENKINS_ARGS
- Furthermore, Moodle requires a which is not contained in a repository. Therefore, configuration files need to be stored at a separate location, from where they can be pulled in. For our scenario, we stored the configuration file at
config.php
, where $target indicates a Moodle branch to build against (e.g., /var/lib/jenkins/moodle-config/config_MOODLE_28_STABLE.php).$JENKINS_HOME/moodle-config/config_$target.php
Jenkins server configuration
For all following steps you need to open Jenkins in your browser.
Install or update the following plugins:
- Xvfb plugin
- Multiple SCMs plugin
- Matrix project plugin
- JUnit plugin
- GitHub plugin
- Job Configuration History Plugin (optional, but very useful)
Configure Jenkins in the following way (Manage Jenkins → Configure System):
- Git
- Add a git installation. Choose an arbitrary name and set the path to
git
- Git plugin
- Set the fields and
Global Config user.name Value
. In our case, we set those values to account and e-mail of a technical GitHub account that is only used by the Jenkins serverGlobal Config user.email Value
Create a job for your integration scenario:
- On the dashboard, select New Item.
- Choose Multi-configuration project and define an Item name without any spaces.
- On the next page, define the following settings (Change to your requirements. Remember our integration scenario described above!):
- GitHub project: URL to the web page of your repository
- Source Code management:
- Choose .
Multiple SCMs
- Use to add two git repositories.
Add SCM
- For the first repository,
- set the URL to .
git://git.moodle.org/moodle.git
- Since this is a public repository, credentials are not required.
- Under Additional Behaviours, add and check the option
Advanced clone behaviours
.Shallow clone
- For the second repository,
- set the URL to the URL of your git repository.
- If this is a private repository, add credentials for accessing it (consider SSH authentication!)
- Under Additional Behaviours, add and, for
Check out to a sub-directory
, enter the path where you would deploy your module in a usual Moodle installation (e.g.,Local subdirectory for repo
), without surrounding slashes.mod/yourmodule
- Under Additional Behaviours, add and check the option
Advanced clone behaviours
.Shallow clone
- Build Triggers:
- Check Build when a change is pushed to GitHub.
- Check Poll SCM. As a schedule, define e.g. for polling every five minutes.
H/5 * * * *
- Configuration Matrix:
- Add two user-defined axes.
- For the first axis, set name to and values to
target
. These values correspond to the branch names used in the Moodle repository.MOODLE_28_STABLE MOODLE_27_STABLE
- For the second axis, set name to and values to
testtype
. These are used later on to perform different test types - be patient :).UnitTest BehatTest
- Check Run each configuration sequentially.
- Build Environment:
- Check Start Xvfb before the build, and shut it down after.
- Build:
- Add Execute shell
- Enter the following commands (Note that we use here, which always holds the current value of
$target
in a particular configuration. Furthermore, this copies an appropriate config.php file into the current workspace):target
git checkout $target;<br />
curl -s https://getcomposer.org/installer | php;<br />
php composer.phar install --prefer-source;<br />
cp $JENKINS_HOME/moodle-config/config_$target.php config.php;
- Add Conditional step (single)
- Run?: , String 1:
Strings match
, String 2:${testtype}
(the motivation is that this command is only run for unit tests. In contrast, the other step will be for behat acceptance tests).UnitTest
- Builder:
Execute shell
- Enter the following commands:
mkdir -p ../moodledata/phpunit;<br />
php admin/tool/phpunit/cli/init.php;<br />
vendor/bin/phpunit --log-junit results/phpunit/phpunit.xml --group mod_ratingallocate || true;
- Add Conditional step (single)
- Run?: , String 1:
Strings match
, String 2:${testtype}
.BehatTest
- Builder:
Execute shell
- Enter the following commands (replace ,
[SeleniumVersion]
, and[ModuleTag]
accordingly):[JobName]
mkdir -p ../moodledata/behat;<br />
php admin/tool/behat/cli/init.php;<br />
java -jar /var/lib/jenkins/selenium/selenium-server-standalone-[SeleniumVersion].jar > /dev/null 2>&1 &<br />
SELENIUM_PID=$!<br />
php -S localhost:8000 > /dev/null 2>&1 &<br />
PHP_PID=$!<br />
vendor/bin/behat --config /var/lib/jenkins/jobs/[JobName]/workspace/target/moodledata/behat/behat/behat.yml --tags '@[ModuleTag]' --format moodle_progress,junit --out ,behatlog || true;<br />
kill $SELENIUM_PID<br />
kill $PHP_PID
- Post-build Actions:
- Add Publish JUnit test result report
- Change the pattern for to the value
Test report XMLs
**/phpunit/phpunit.xml,**/behatlog/*.xml
- Save the configuration and start the first build to test it.