Check your version

This video covers a topic in Drupal 7 which may or may not be the version you're using. We're keeping this tutorial online as a courtesy to users of Drupal 7, but we consider it archived.

Alternate resources: 

Learning Test Case Basics by Writing a Hello World Test

Video loading...

  • 0:01
    Automated Testing in Drupal 7 with SimpleTest
  • 0:03
    Learning Test Case Basics by Writing a Hello World Test
  • 0:05
    with Joe Shindelar
  • 0:07
    Like any good programming tutorial, now
  • 0:10
    that we've got some terminology and environment setup out of the way,
  • 0:13
    we're ready to jump in and write a Hello World Test.
  • 0:18
    Hello World exercises are a great way
  • 0:20
    to learn about how tests are discovered by Drupal,
  • 0:23
    and to demonstrate the bare minimum requirements
  • 0:26
    to get our tests to run.
  • 0:28
    In this lesson, we'll be expanding upon a simple Hello World module
  • 0:32
    to add our first test case, looking at some of the documentation
  • 0:36
    for SimpleTest and finally, running our first custom test.
  • 0:40
    If you want to follow along, you can grab a copy of the code
  • 0:43
    for the Hello World module that we'll
  • 0:45
    be starting with, attached to this page.
  • 0:48
    After completing this lesson, you should be able to write a new test
  • 0:52
    case class that extends the Drupal web test case,
  • 0:55
    have Drupal find your new test case, and be able to run your tests.
  • 1:01
    We can start by taking a look at the Hello World module, which
  • 1:04
    we're going to be writing a test for.
  • 1:06
    I've got the module downloaded already.
  • 1:08
    It's in my sites/all/modules/custom directory.
  • 1:11
    You can grab a copy of the code from this page
  • 1:14
    that the video is attached to, if you would like to follow along.
  • 1:17
    There is a helloworld.info file-- just the standard Drupal info
  • 1:20
    file-- name, description, and version of Drupal core
  • 1:23
    that our module is compatible with.
  • 1:25
    And then in the helloworld.module file,
  • 1:27
    there's just a little bit of code, an implementation of hook_menu,
  • 1:31
    which creates a menu item at the URL helloworld
  • 1:34
    and calls our page callback helloworld_hello_page.
  • 1:38
    If I look at that function, I can see
  • 1:40
    that it's returning a string of text.
  • 1:43
    The text says, "Hello World.
  • 1:44
    Welcome to Drupal."
  • 1:45
    So this module is going to provide us with a page
  • 1:47
    that we can navigate to at a URL that contains this content.
  • 1:51
    One of the things I really like to do when writing tests,
  • 1:54
    is try and walk through the steps in my browser
  • 1:57
    first, so I can get an idea of what it is that I'm going
  • 2:00
    to be asking SimpleTest to do for me.
  • 2:03
    Since most tests in Drupal are functional tests,
  • 2:06
    there really just simulating the same things
  • 2:08
    that I would do, clicking around in my browser.
  • 2:10
    So let's do that.
  • 2:11
    If I switch over to our site on my browser,
  • 2:14
    with the Hello World module enabled, I now
  • 2:17
    have an item in the navigation menu on the left hand
  • 2:20
    side, that reads Hello World.
  • 2:22
    I can click on that text and it takes me to a page at the URL
  • 2:27
    /helloworld that contains the content, "Hello World.
  • 2:30
    Welcome to Drupal."
  • 2:32
    So what I'd like to do is simulate navigating to this page.
  • 2:36
    For our use case, we'll just simulate navigating to this page
  • 2:39
    by typing the URL directly into the browser.
  • 2:42
    Once the page is loaded, I want to confirm
  • 2:45
    that this string of text, "Hello World.
  • 2:48
    Welcome to Drupal," appears on the page.
  • 2:51
    In SimpleTest terms, I'm going to assert that this text is present.
  • 2:57
    And if it is, I'll pass the test, and if it's not,
  • 3:00
    I'll fail the test.
  • 3:01
    Let's switch back to our editor and start writing the test.
  • 3:05
    The first thing we're going to need to do
  • 3:06
    is create a file that will hold our new test class.
  • 3:11
    So inside of the Hello World module, I'm
  • 3:13
    going to create a subdirectory named tests.
  • 3:16
    And inside of that subdirectory, I'm going to create a file.
  • 3:19
    And I'll name it helloworld.test.
  • 3:22
    And this is just a PHP file.
  • 3:25
    The name of the file isn't really important.
  • 3:27
    The .test extension isn't necessarily even required,
  • 3:30
    though it is considered best practice.
  • 3:32
    And the convention in Drupal is, any file that contains a test
  • 3:35
    class ends with a .test extension.
  • 3:38
    If my module only has one test class,
  • 3:41
    or one file that contains all of my test cases,
  • 3:43
    I'll just name it my module, module name, .test.
  • 3:48
    In order for Drupal to know about the content of this file
  • 3:52
    and load it when it's necessary, I need
  • 3:55
    to declare this file in my modules.info file.
  • 3:58
    So in helloworld.info, I'm going to add a new line.
  • 4:02
    Files, square brackets, = tests/helloworld.test, like so.
  • 4:10
    This allows Drupal to locate the file tests/helloworld.test and know
  • 4:16
    that it contains one or more classes.
  • 4:18
    That way, in the future, when Drupal needs to instantiate
  • 4:21
    a copy of that class, it will know where
  • 4:23
    to look without me having to load the file manually.
  • 4:27
    Back in our .test file, we're going to need to create a new class.
  • 4:32
    Each test case in SimpleTest is an extension of either the Drupal web
  • 4:38
    test case or Drupal unit test case classes,
  • 4:41
    depending on whether or not you're running
  • 4:43
    a functional test or a unit test.
  • 4:45
    We're going to be writing a functional test,
  • 4:47
    so we'll extend the Drupal web test case.
  • 4:51
    So I'll start by adding some documentation to my file.
  • 4:54
    And I'll say, this contains tests for the hello world module.
  • 5:00
    And then I'm going to create a new class.
  • 5:02
    We'll call this class HelloworldTests
  • 5:07
    extends DrupalWebTestCase.
  • 5:11
    I can name my test class here pretty much anything I want to.
  • 5:15
    The name isn't really important.
  • 5:16
    I recommend prefixing your class name with the name of your module,
  • 5:20
    so that you don't run into any namespace conflicts.
  • 5:22
    That's just best practice.
  • 5:24
    But you could name it whatever you wanted to.
  • 5:26
    We've got a module, HelloworldTests.
  • 5:29
    In an earlier lesson, we talked a little bit about writing tests.
  • 5:32
    And we said that every test case that we write
  • 5:35
    is an extension of one of the base test classes,
  • 5:38
    in this case Drupal web test case.
  • 5:40
    And that there are a couple of methods that we need to implement
  • 5:44
    in our test case, to ensure that our tests get set up and run properly.
  • 5:49
    Those are the getInfo and setUp methods.
  • 5:53
    Let's start by doing that.
  • 5:55
    So I'm going to create a new public method.
  • 5:57
    It's actually going to be a static method.
  • 6:00
    It's important that we declare this as static,
  • 6:02
    otherwise SimpleTest is going to complain.
  • 6:04
    And this is just going to return an array.
  • 6:07
    The array is going to contain metadata about our test.
  • 6:12
    Metadata about our test case.
  • 6:14
    That array is going to contain just a couple of keys,
  • 6:17
    name-- so the name of our test, or the specific test
  • 6:21
    case-- a description, and a group.
  • 6:26
    I'm specifically giving this the human readable
  • 6:28
    name "Hello World Group."
  • 6:29
    So when we look at this in the user interface
  • 6:31
    we can distinguish between name and group.
  • 6:35
    Normally I would probably just name these two things the same.
  • 6:38
    Name and group would just be Hello World.
  • 6:40
    With that in place, we should actually
  • 6:42
    be able to get Drupal to recognize our test case.
  • 6:45
    There's nothing for it to run, but it should show up.
  • 6:47
    If we switch back to our browser, the first thing I'm going to do
  • 6:50
    is clear the cache.
  • 6:51
    So I go to Configuration, Performance,
  • 6:54
    and I'm going to click the Clear All Caches button.
  • 6:56
    This will tell Drupal to go and re-read the helloworld.info file,
  • 7:01
    locate the helloworld.test file, and now know
  • 7:04
    about the existence of the Hello World test class.
  • 7:09
    And if we go to Configuration, scroll down and go to testing,
  • 7:13
    in the list here I should be able to find Hello World.
  • 7:16
    So I've got Hello World Group, and if I click the arrow to open it,
  • 7:19
    I've got Hello World and, "Tests for the Hello World module."
  • 7:23
    These correspond directly to the keys
  • 7:25
    that we just set inside of our test cases, get info method.
  • 7:29
    You can see here the name, the description, and the group.
  • 7:34
    All right.
  • 7:34
    There's nothing to do in this test yet, so I'm not going to run it.
  • 7:38
    Instead, I'm going to switch back to my editor and add a setup method.
  • 7:44
    We've talked about this a few times, but whenever Drupal runs a set
  • 7:47
    of tests, for each individual test case--
  • 7:51
    a test case being a class, like this, HelloWorldTests--
  • 7:55
    so for each test case, Drupal rebuilds the entire environment.
  • 8:01
    It creates a whole new set of tables,
  • 8:03
    it installs Drupal from scratch, it runs the standard installation
  • 8:06
    profile, and then it just starts from there.
  • 8:09
    In order to test our hello world module,
  • 8:12
    the module needs to be enabled.
  • 8:14
    So we're going to provide a setup function in our test
  • 8:17
    that says, let's enable this module.
  • 8:20
    By default Drupal doesn't enable the Hello World module.
  • 8:23
    So if we add a setup method to our test case, if it exists,
  • 8:27
    SimpleTest will call it.
  • 8:29
    If it doesn't, it'll skip it.
  • 8:31
    What we're really doing though, is overriding the parent
  • 8:34
    set-up method, which is part of the Drupal web test case.
  • 8:37
    So I'm going to call that parent method, so it can do all
  • 8:40
    of the things that it needs to do during setup.
  • 8:42
    In addition, I'm going to pass in an argument, which is an array of all
  • 8:47
    the modules that I would like to have
  • 8:48
    enabled when my test case is running.
  • 8:51
    So this will say, after you've run the standard installation profile,
  • 8:55
    also enable the Hello World module.
  • 8:58
    In future lessons, we'll take a look at other things
  • 9:00
    that you might do in the setup here.
  • 9:02
    But it's all about configuring the environment
  • 9:04
    in which your tests are going to run.
  • 9:06
    Then you might do things like enable a module.
  • 9:09
    You also might do things like create the users that you need to navigate
  • 9:12
    your site, or create the content that it
  • 9:14
    is that you're trying to test.
  • 9:16
    Of course, we should have some documentation for our function
  • 9:19
    here, so I'll just add a simple dock block that says, "Perform
  • 9:22
    any setup tasks for our test case."
  • 9:25
    And then finally, I'm going to write a test.
  • 9:27
    In order to do that, I need to create a specially named method
  • 9:31
    on this Hello World tests class.
  • 9:34
    I'm going to create a new public method,
  • 9:36
    and I'm going to call it tests-- testHelloWorld.
  • 9:39
    I'm going to add a few lines so this is easier to see.
  • 9:42
    The way that this works, is that SimpleTest will
  • 9:45
    locate any method on our test class.
  • 9:48
    This starts with the prefix test, like so.
  • 9:52
    Test, and then any name we want.
  • 9:53
    So ours is testHelloWorld, but it could be testRainbows
  • 9:56
    or testUnicorns or whatever we want to call it.
  • 10:00
    In a lot of cases, we might have multiple tests
  • 10:03
    that make up an individual test case.
  • 10:06
    Right now, we've just got one.
  • 10:08
    So we've got the test method.
  • 10:11
    SimpleTest will know that this method exists,
  • 10:14
    it will call this method, and it will expect this method
  • 10:18
    to contain some number of assertions that are checked.
  • 10:22
    If they pass, this test passes.
  • 10:24
    If they fail, this test fails.
  • 10:27
    Within the testHelloWorld method is where we're
  • 10:30
    effectively driving the SimpleTest browser.
  • 10:33
    We can do things like tell it to navigate to a page,
  • 10:35
    using this drupalGet 'helloworld.'
  • 10:39
    And once on the page, we can tell the browser
  • 10:41
    to perform one or more assertions.
  • 10:43
    We're going to say $this->assertText.
  • 10:45
    The text that I want to assert here is the same
  • 10:49
    as the URL helloworld that we navigated to.
  • 10:52
    If I switch back to my browser and do this once more,
  • 10:55
    I can navigate to that page.
  • 10:57
    So I'll go to the home page and click Hello World.
  • 10:59
    So I'm on my page provided by our module.
  • 11:01
    It's got this text.
  • 11:02
    I'm just going to copy and paste it right into our module,
  • 11:05
    or into our test.
  • 11:06
    Because that's what I want to do.
  • 11:07
    I want to assert that this text exists
  • 11:09
    when somebody visits the page.
  • 11:11
    So I'm going to assertText.
  • 11:13
    And then I'm going to pass in another message that
  • 11:15
    says, page content.
  • 11:19
    I won't go into too much detail about this assert function
  • 11:23
    and how this works, because we'll be covering that
  • 11:26
    in much more depth in the next lesson.
  • 11:28
    But the assert here is basically saying,
  • 11:31
    look at the contents of the page in this given context,
  • 11:35
    verify that the text exists, and here's the message that I want
  • 11:39
    to use in the log file when you're logging that this test happened,
  • 11:44
    and whether or not it passed.
  • 11:45
    When we run our test this'll make a little more sense.
  • 11:48
    This is a really simple example of a test.
  • 11:52
    Navigate to a URL, check that some content
  • 11:55
    exists after installing our module.
  • 11:58
    So I can save that.
  • 11:59
    Let's switch back to our browser.
  • 12:01
    I'm going to go to Configuration, and then testing.
  • 12:04
    And I'm going to run the Hello World tests.
  • 12:06
    So I'll scroll down, find the Hello World group.
  • 12:08
    I'll just run the whole group, because we've
  • 12:10
    only got one test right now.
  • 12:12
    And click Run tests.
  • 12:15
    When I do that, for our Hello World test case,
  • 12:19
    and any test case that's being run, SimpleTest
  • 12:22
    will create a whole new Drupal environment.
  • 12:24
    It'll then install Drupal using the standard installation profile,
  • 12:29
    and call your test cases set up method.
  • 12:32
    That set-up method can do things like enable additional modules,
  • 12:36
    in our case enable the Hello World module.
  • 12:38
    And then it'll call a new test method, or a method that starts
  • 12:42
    with the prefix test, which is expected to contain some assertions
  • 12:46
    that are verifying whether or not the functionality of your page
  • 12:49
    works.
  • 12:50
    Looks like ours worked.
  • 12:52
    If I tip this open, you can see the setup worked.
  • 12:56
    It enabled the Hello World module.
  • 12:59
    After doing so, it navigated to the URL /helloworld,
  • 13:03
    just like we asked it to.
  • 13:05
    It found a valid response on that page.
  • 13:08
    Here's the verbose output of that.
  • 13:11
    I can click on it, and sure enough our module's been enabled.
  • 13:14
    And you can see the content is present.
  • 13:16
    And then it ran our assertion, and displayed the log message here.
  • 13:20
    This page content is present.
  • 13:23
    So that's a really simple example of something
  • 13:25
    that we can do with the test.
  • 13:27
    The primary takeaway here is, in order to write a test,
  • 13:30
    you need to create a new .test file with a class in it that is
  • 13:33
    an extension of the Drupal web test case.
  • 13:36
    And then include that .test file in your modules.info file,
  • 13:40
    in order to ensure that Drupal can find it.
  • 13:43
    Finally, we also need to make sure that each of our test cases
  • 13:47
    provides a static getInfo method, which
  • 13:50
    returns metadata about our test.
  • 13:52
    And a set-up method, which allows us to perform
  • 13:55
    any additional configuration that is necessary in order
  • 13:58
    to prepare the environment for testing.
  • 14:00
    In the next lesson, we'll look at various different assertions
  • 14:03
    that we can make in a test case.

Learning Test Case Basics by Writing a Hello World Test

Loading...

In this lesson we'll write a hello world test that navigates to the front page of a standard Drupal installation and verifies the existence of the text, "No front page content has been created yet.". This will allow us to walk through creating a .test file, adding it to our modules .info file, as well as cover the basics of extending DrupalWebTestCase to write our own test case. For this lesson we'll use the helloworld sample module as a starting point and expand it to add a very basic test. The goal being to gain a better understanding of how the SimpleTest module discovers, and runs our tests. Then in future lessons we can expand on our test case to add more robust features.

All SimpleTest tests are an extension of either the DrupalWebTestCase (we'll focus on this one), or the DrupalUnitTestCase base classes. There are two pieces to the discover process. Writing a new class that extends one of the base classes, and then declaring the file that contains this new class in your module's .info file so that the file and it's code are indexed and inserted into the registry.

Create a new file inside the helloworld module's directory: tests/helloworld.test. The convention is to name files that contain test classes with a .test extension. Similar to how module file, despite being purely PHP, are named with a .module extension.

Then we'll add a basic skeleton test class like so:


class HelloworldTests extends DrupalWebTestCase {
  /**
   * Metadata about our test case.
   */
  public static function getInfo() {
    return array(
      'name' => 'Hello World',
      'description' => 'Tests for the Hello World module.',
      'group' => 'Hello World Group',
    );
  }
}

Our class includes a getInfo() method, it's required, and it returns a simple associative array with meta-data about our test. This information is used by the SimpleTest UI and other test runners to provide human readable information about our tests and to do things like group like tests together. When you view the lists of tests in the SimpleTest UI, you're seeing the 'name', and 'description' provided by your test classes' getInfo() method.

All tests should have a setUp() method as well. This method is called by the test runner after Drupal has been installed, but before our tests are run. It gives us the chance to perform any additional configuration on the environment within which the tests are running. In our case, we need to enable the helloworld module since it's not part of the default install profile. We can do that by delegating to the parent classes' setUp() method and passing an array of modules we want enabled. That might look something like this:


/**
 * Perform any setup tasks for our test case.
 */
public function setUp() {
  parent::setUp(array('helloworld'));
}

Finally, we need to provide at least one method whose name starts with "test". This method, and all others whose name starts with test will be called in succession by the test runner and are expected to contain the assertions that make up our individual test.


public function testHelloWorld() {
  $this->drupalGet('helloworld');
  $this->assertText('Hello World. Welcome to Drupal.', 'The page content is present.');
}

This test will navigate to the url /helloworld, and then verify that the text "Hello World. Welcome to Drupal.", is displayed on the page.

In order for our test to show up in the SimpleTest UI we need to add it to the registry. We can do so by modifying the helloworld.info file and adding the line files[] = tests/helloworld.test to the file. Then clear the cache and Drupal should discover your new test case and allow you to run the tests either through the SimpleTest UI or with drush.

Downloads: 
Log in or sign up to download companion files.