We’re learning how to move faster with Drupal, moving changes from a dev’s laptop to production quickly while maintaining (if not increasing) quality. In part 1 of this Continuous Drupal series, we covered how to get up and running with Drupal using a modern toolset. In this post we’re going to continue where part 1 left off and bring our Drupal website into CircleCI. We’ll run QA tests on the site to make sure everything is running as expected, and optionally PHPUnit test for custom modules or themes we may have. Let’s dive in.
Now that we have a Drupal website managed with Git and Composer, we’re in a great position to use tools such as CircleCI, Behat, and PHPUnit to test our website automatically.
Testing a Drupal 8 Website With Behat
Behat allows the description of how certain UI-based features should work in a near-English language. If you’re familiar with the concept of “User Stories”, Behat lets us write user stories in code in a way that we can test automatically, called Behaviour-Driven Development.
We’re going to install Behat and related tools. We’ll want to be within the
app directory inside our Drupal container to do this.
docker-compose ps # to get our container name docker exec -it continuousblog_drupal_1 bash composer require --dev behat/behat composer require --dev behat/mink composer require --dev behat/mink-extension composer require --dev drupal/drupal-extension
default: suites: default: contexts: - FeatureContext - Drupal\DrupalExtension\Context\DrupalContext - Drupal\DrupalExtension\Context\MinkContext extensions: Behat\MinkExtension: goutte: ~ selenium2: ~ base_url: http://localhost/ Drupal\DrupalExtension: blackbox: ~ api_driver: 'drupal' drupal: drupal_root: 'web'
Then we’re going to have Behat initialize and run
-dl to see the definitions list. Being able to view this list confirms that everything installed correctly.
vendor/bin/behat --init vendor/bin/behat -dl
Testing User Behavior
Our Behat tests will go in the
/app/features/ directory in our container. We’re going to create a quick generic test, in order to make sure our system is working on demo just as the test workflow works.
Create the file
Feature: Test Features Some test scenarios to make sure the website is generally working. @api Scenario: Run cron Given I am logged in as a user with the "administrator" role When I run cron And am on "admin/reports/dblog" Then I should see the link "Cron run completed"
Now we can run our Behat tests with:
vendor/bin/behat Feature: Test Features Test scenarios to make sure the website is generally working. @api Scenario: Run cron # features/global.feature:4 Given I am logged in as a user with the "administrator" role # Drupal\DrupalExtension\Context\DrupalContext::assertAuthenticatedByRole() When I run cron # Drupal\DrupalExtension\Context\DrupalContext::assertCron() And am on "admin/reports/dblog" # Drupal\DrupalExtension\Context\MinkContext::visit() Then I should see the link "Cron run completed" # Drupal\DrupalExtension\Context\MinkContext::assertLinkVisible() 1 scenario (1 passed) 4 steps (4 passed) 0m1.25s (13.18Mb)
At this point, we have a basic example for using Behat to test Drupal. The next step is to hook all of this up to CircleCI. Before we do so, let’s save our progress with Git.
exit # to exit the container git status # you should recognize everything outside of the */files/* directory git add . git commit -m "Configure Behat and first test."
Now we’re going to set our Drupal website up on CircleCI. If this is your first time using CircleCI, make your way through the Getting Started Doc first.
The CircleCI configuration file should be located at
.circleci/config.yml and ours will look like this:
version: 2 jobs: build: docker: - image: cibuilds/drupal:latest - image: mariadb:10.2 environment: MYSQL_DATABASE: drupal MYSQL_ROOT_PASSWORD: HorriblePassword MYSQL_ROOT_HOST: "%" environment: BLUEMIX_ORG: CircleCI BLUEMIX_SPACE: dev working_directory: /project/app steps: - checkout: path: /project - run: name: "Setup Database & Server" command: | echo "127.0.0.1 db" >> /etc/hosts sleep 20 mysql -uroot -pHorriblePassword -h127.0.0.1 drupal < ../db/drupal-db-dump.sql service apache2 start - run: name: "Install Dependencies" command: | composer install - run: name: "Behat Tests" command: vendor/bin/behat
Instead of using Docker Compose, as we did in the previous blog post, we’re using CircleCI and its “Docker Executor” to create our build environment. We’re going to do a walkthrough of the CircleCI Configuration in part 3 of this series. For now, I just want to touch on the “Setup Database & Server” step.
Managing The Database
When managing multiple environments, you’re likely to have multiple database locations. One each for production, CI, staging, dev, etc. For certain environments (such as dev) you may get away with using a lightweight fake DB. Many times you’re going to need to work on real data. This is done by making copies (dumps) of the DB and importing them into other environments. The key is the direction the data flows.
Always Move DB Data Downstream
This is important enough that it warrants its own header. When moving copies of DB data around, always start by copying the data from production. Then you can import it into staging or somewhere else. You may even then move staging data to your local machine. This practice prevents data loss. If you start with a DB on your local machine, and move it to production, you may lose users, posts, and more that were created since the local dev DB was last created.
echo "127.0.0.1 db" >> /etc/hosts - Our Drupal settings file knows that the database hostname that we set previously is
db. This line always that hostname to work within the CircleCI container.
Tracking DB Export
For this example, the directory at the root of our repo
./db was created to hold DB dumps in the
.sql format. There’s a dump from
mysqldump in there from our local DB. Once your website is in production, you’ll want to retrieve the DB dump from there. It’s common practice for sites with sensitive data to sanitize the DB before importing it from production to other environments. Especially when these additional environments might be less secure. If there’s still sensitive information in the DB dump, you may not want to track it with Git as we’re doing here.
Lastly, Hosting Our Drupal Website
In the 3rd part of this “Continuous Drupal” series, we’re going to find a place to host our Drupal website using Kubernetes, allowing us to scale the hosting infrastructure as our site becomes more and more popular.
Questions & Keeping This Post Updated
If you have questions, or something to add to this post, please let us know at CircleCI Discuss.