Chapter 9. Eliminating Stress with the Help of Automation

So far, we've covered almost every aspect of what testing in practice is. We've learned what can be done with Codeception at all the levels of testing: unit, functional, and acceptance. We've covered additional resources on how to improve and debug your tests while looking at architectural choices and long-term considerations.

To keep it short, in this chapter, we're going to take the final step, which is nowadays considered as the best practice: continuous integration.

We are going to understand what a continuous integration system is, and what the choices that we have are. We'll also start working with Jenkins.

In this chapter, we will discuss everything that we need to install and configure. We will run our builds and obtain the required level of automation for our project. We'll cover the following topics:

  • Automating the build process
  • Creating the required build files
  • Configuring the Jenkins build
  • Going forward

Automating the build process

There are two aspects that you should always take into consideration when planning and implementing your tests. Firstly, 100 percent code coverage won't help you in removing the possibility of having or introducing a bug, which means that exploratory manual testing will always be needed, and it will have to be factored in while writing your initial draft of the master test plan. Secondly, until now, all the tests and reports that we've generated for such a small project can be run manually by whoever changes the code.

When the size of your code starts to grow and you start to support hundreds of classes and multi-faceted frontend functionalities, when your code lives past the first month and more than one developer will need to access it over and over again, all the knowledge related to tests and how they work or what kind of information can be extracted from them will become more and more difficult to maintain. The worst part is that most likely nobody will use it without any struggle.

Here, you have two choices: accept the fate that your tests will be long forgotten and nobody will know what's been covered and what needs to be covered, or start automating all this by forcing some sort of automated code revision, which might trigger reports and e-mails to warn about anything that can potentially go wrong, or has already gone wrong.

Introducing continuous integration systems

Extreme Programming (XP) has introduced the concept of continuous integration (CI). Nowadays, it's used in many companies as a part of their QA procedures, regardless of the practice adopted.

Whether frequent integration is better than continuous integration is something I'd prefer to leave out of this discussion. The main difference between the two is based on the frequency at which the integration happens. On top of this, CI has been conceived to be a part of TDD, and it is specifically aimed at running tests before merging any features into the active branch. This is done to ensure that the new functionality won't break the existing one.

Systems like Jenkins (formerly known as Hudson), Bamboo, CruiseControl, and Travis, have been created so that the work of the different developers can be integrated and tested before being shipped. This also ensures that certain quality standards are reached so that we can avoid introducing incoherence in the code base, and we can report the results to the developers.

These software systems perform a multitude of tasks. They're made in such a way that they can support any programming language and testing framework.

Usually, they're built for providing a flexible way of defining your integration work flow: code check out, preparation, build (which usually includes testing and other quality assurance-related tasks), report publishing, artifact creation, and eventually deployment. All of these steps can be controlled within the system and/or through scripting of various types. For instance, you can use Ant or Maven in Travis, Bamboo, or Jenkins. Apart from the basic functionality, several plugins are normally available in these systems for extending the functionality of integrating additional third-party applications, libraries, and services.

Before getting into the nitty-gritty details of configuring the continuous integration system of our choice, we may want to first see what's available and how we can choose.

Available systems

There are a number of CI systems, and many of them have been created specifically for certain programming languages; therefore, they can perform only a restricted set of operations.

The more complex the system is, the more time it takes to prepare it to behave as we want it to, but you'll have the ability to perform as many functions as required, and you will also have the ability to switch them on or off on a per-project basis.

The most well-known system is Jenkins. It is an open source system (http://jenkins-ci.org). It was forked in 2011 from Hudson, after a dispute with Oracle. It is a CI system written in Java, and it became popular as an alternative to CruiseControl. It has always been regarded as the most polyfunctional CI system available. This is also because its huge community provides hundreds of different plugins for any kind of functionality.

The only problem I see with Jenkins, apart from configuring it, is hosting it, although, installing and maintaining it has always been easy for me.

You might be unable to host the system yourself, so you may want to look for something that provides a hosted solution. Bamboo is another choice that is said to be particularly straightforward if you are migrating from Jenkins. It also provides out-of-the-box integration with other Atlassian products, such as Jira, BitBucket, HipChat, and so on.

As a matter of choice, we'll be looking into Jenkins, installing the required plugins, and then creating the build by using the Apache Ant scripts.

Installing and configuring Jenkins

There isn't much to be said about the installation of Jenkins. As the installation page shows, it's cross-compatible and it can be run on operating systems, such as Windows, Linux, Unix, and Docker. For more information, check out https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkins.

Note

It's important to remember that its only requirement is Java, so you should have up-to-date versions of JDK and JRE.

Most distributions already package Jenkins and provide it with their official package repositories, thereby solving most of the problems of dependencies.

The installation on *nix systems will create its own dedicated user Jenkins, which will be used for doing all the operations that will be run through its interface. Never run Jenkins as a superuser. This can cause security issues. The workspace where the projects will be checked out is normally located at /var/lib/jenkins/home/workspace, which you can inspect manually if something goes wrong.

When started, Jenkins will be listening on port 8080 (not always, be sure to read the post-installation instructions, if any, or check the opened ports using netstat -ltn on Linux), and it will be accessible from the web browser.

Tip

If you want to expose your service to a wider audience, then you might want to install a proxy in order to serve it from port 80, with whichever hostname you want. We won't cover this aspect, but Jenkins provides additional documentation on how to achieve this.

So, let's open http://<yourhostname>:8080 in our browser, and let's start configuring the basics.

Understanding the Jenkins organization

Before doing this, you may need to understand how Jenkins is organized. If you are already experienced with it, then you may want to skip over to the next section.

There are only two sections that you need to keep an eye out for:

  • The jobs list
  • The management panel

The first one is where you will normally land, and it is what you will be working on most of the time.

In the Jenkins terminology, a job is a specific set of rules and operations that needs to be performed in a specific project. You can have different jobs for the same project, which perform slightly or completely different operations, and these can be triggered sequentially.

A build is the process of executing a job. We will cover this and see what we can achieve with a single build by configuring the various aspects of the job. The build can result in the creation of one or more artefacts, deploy the build result somewhere or trigger some other job or process within Jenkins itself, or outside of it.

You need to fix Jenkins' security immediately after installing it, unless you will be the only person accessing it and the server where it's installed will have no external access, it's probably better to navigate to http://jenkins:8080/configureSecurity/.

You can set up whichever authentication system you want, using PAM, LDAP, or its internal user database. We will be using the latter, but remember that if you're willing to do something a bit stronger or interconnected, there may be additional steps that you may need to follow. Most of the interface forms have a few small info buttons that you can use to display some information, as shown in the following screenshot:

Understanding the Jenkins organization

View of the Configure Global Security page with an open info box

The second aspect that requires a little thinking from your side is how Jenkins will be accessing and checking your repository.

Any major online repository provider, such as GitHub and BitBucket will let you create a so-called deployment key, which is used for a read-only access to the repository.

For anything more complex, such as merging and pushing your branches, you would need to set up its own user, as shown in the following screenshot:

Understanding the Jenkins organization

The deployment keys setup page in BitBucket, available from the settings of each repository

If you have more repositories that are hosted by different places, then you need to set up as many credentials as needed for Jenkins. This can be accomplished by going to http://jenkins:8080/credential-store/ (or Home | Credentials | Global Credentials). As you can see, there's a lot behind the scenes, so feel free to explore and read the documentation for understanding what's needed. Normally starting with the setup of the global credentials may be enough, but there are cases where a non-global configuration is needed.

In order to do so, we need to create the SSH key pairs for the user jenkins first.

peach ~ $ sudo -s
root peach # su jenkins -
jenkins peach $ cd ~
jenkins ~ $ pwd
/var/lib/jenkins
jenkins ~ $ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/jenkins/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /var/lib/jenkins/.ssh/id_rsa.
Your public key has been saved in /var/lib/jenkins/.ssh/id_rsa.pub.
The key fingerprint is:
ff:be:b1:ee:c2:69:82:96:00:e4:9d:dd:67:cf:1e:d7 jenkins@mangotree
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
| . . o. .        |
|+ . *.oo  .      |
|.o o .o+S. E     |
|+ o   .+o        |
|+*. . o.         |
|+. . .           |
|                 |
+-----------------+

Now that you have your SSH key, you need to grab the public key, which is stored at /var/lib/jenkins/.ssh/id_rsa.pub, and then copy it to your repository as a deployment key. You can copy it to the clipboard by using the following command:

root jenkins # xclip -sel clip < /var/lib/jenkins/.ssh/id_rsa.pub

This has been done through the root user because the jenkins user won't have the X display setup in its environment and this is likely to cause the error shown here:

No protocol specified
Error: Can't open display: :0

Tip

If you are on a headless server, then you won't have many choices. You can either scp on the file to your local machine or cat the file and then paste it in the browser manually.

Now that you have your deployment key set up, you need to go back to Jenkins and then navigate to the credentials store. Once there, set the username as jenkins (which is the system's user name), and set the private key as From the Jenkins master ~/.ssh.

The following sections will cover the installation of additional plugins and the configuration of the job.

Installing the required plugins

Now that you have covered the basic configuration of Jenkins, you need to install the required plugins so that everything works as expected.

This section is normally handled easily by Jenkins. There's a project that is specifically for the PHP projects on Jenkins. You can find it at http://jenkins-php.org. Not only does the project list the following plugins, but it also lists a meta plugin, which is available on Jenkins, and it will download all the required plug-ins.

  • Checkstyle: This is used for processing the PHP_CodeSniffer log files in the Checkstyle format
  • Clover PHP: This is used for processing the PHPUnit's Clover XML log file
  • Crap4J: This is used for processing the PHPUnit's Crap4J XML log file
  • DRY: This is used for processing the phpcpd log files in the PMD-CPD format
  • HTML Publisher: This is used for publishing the documentation generated by phpDox
  • JDepend: This is used for processing the PHP_Depend log files in the JDepend format
  • Plot: This is used for processing the phploc CSV output
  • PMD: This is used for processing the PHPMD log files in the PMD format
  • Violations: This is used for processing the various log files
  • xUnit: This is used for processing the PHPUnit's JUnit XML log file

The preceding list is taken from http://jenkins-php.org/installation.html, and it might change in the future, so keep that in mind.

If you navigate to Manage Jenkins | Manage Plugins, then you can search for the plugin php and select Install without restart. When you are on the installation page, select the Restart Jenkins when installation is complete and no jobs are running option (sometimes the installation page does not refresh itself automatically, so you might have to refresh the page; a list of plugins will get installed even if you navigate away from this page).

Now, you need to install the tools needed by these plugins, so open the composer.json file and then add the following to your require-dev section:

// composer.json
"phploc/phploc": "@stable",
"pdepend/pdepend": "@stable",
"phpmd/phpmd": "@stable",
"sebastian/phpcpd": "@dev",
"yiisoft/yii2-coding-standards": "*",
"theseer/phpdox": "@stable"

Now, run the composer update to install these effectively.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset