TeamCleaner test

Now that we have that covered, it's time to write our first Kernel test. And a nice simple example can be to test the TeamCleanerQueueWorker plugin we created in Chapter 14, Batches, Queues, and Cron. If you are wondering why this cannot be tested using the ultra-fast unit testing methodology, the answer is that its single method doesn't return anything. Instead, it alters database values that we need to access in order to check it happened correctly.

The test class goes naturally in the tests/src/Kernel folder of our module and can start off like this:

namespace Drupal\Tests\sports\Kernel; 
 
use Drupal\KernelTests\KernelTestBase; 
 
/** 
 * Test the TeamCleaner QueueWorker plugin. 
 * 
 * @group sports 
 */ 
class TeamCleanerTest extends KernelTestBase {}  

The namespace is consistent with the ones we've seen so far and we have the correct PHPDoc annotations to register the test. Moreover, this time, we are extending from KernelTestBase. Do pay attention to the actual version of this class because the one that comes from the old Simpletest framework is also called KernelTestBase. So make sure you extend the correct one as seen in the use statement.

The first thing we need to do is specify which modules we want loaded when running this test. For our case, this is the sports module so we can add a class property that contains this name:

/** 
 * Modules to enable. 
 * 
 * @var array 
 */ 
protected static $modules = ['sports'];  

Specifying a list of modules here does not actually install them but simply loads and adds them to the service container. So yes, we have access to the module and code as well as the container. But that also means that schemas defined by these modules are not actually created so we need to do that manually. The same is true for the configuration the module is shipped with. But we can handle these things in the setUp() method or in the actual test method itself. We'll opt for the latter because, in this case, we only have one test method in the class. And the whole thing can look like this:

/** 
 * Tests the TeamCleaner::processItem() method. 
 */ 
public function testProcessItem() { 
  $this->installSchema('sports', 'teams'); 
  $database = $this->container->get('database'); 
  $fields = ['name' => 'Team name']; 
  $id = $database->insert('teams') 
    ->fields($fields) 
    ->execute(); 
 
  $records = $database->query("SELECT id FROM {teams} WHERE id = :id", [':id' => $id])->fetchAll(); 
  $this->assertNotEmpty($records); 
 
  $worker = new TeamCleaner([], NULL, NULL, $database); 
  $data = new \stdClass(); 
  $data->id = $id; 
  $worker->processItem($data); 
  $records = $database->query("SELECT id FROM {teams} WHERE id = :id", [':id' => $id])->fetchAll(); 
  $this->assertEmpty($records); 
}  

And the use statement:

use Drupal\sports\Plugin\QueueWorker\TeamCleaner;  

Since the TeamCleaner plugin removes teams, it's enough to only install that table. We can do that using the parent installSchema() method to which we pass the module name and table we want installed. We don't actually deal with players so we should avoid doing unnecessary work like the creation of the players table.

Then, very similar to how we do it in real code, we get the database service from the container and add a record to the teams table. This will be the test record that we delete so we remember its $id. But before we test this, we want to make absolutely sure that our record got saved. So we query for it and assert that the result is not empty. The assertNotEmpty() method is another helpful assertion that we can use when dealing with arrays.

Now that we are certain the record is in the database, we can "process" it using our plugin. So we instantiate a TeamCleaner object, passing all its required dependencies—most importantly the database service. Then we create a simple object that mimics what the processItem() method expects and calls the latter while passing the former to it. At this point, if our plugin did its job correctly, the team record should have been deleted from the database. So we can query for it and this time assert the opposite of what we did before: that the query comes back empty.

And with this, our test is finished. As always, we should actually run it and make sure it passes:

../vendor/bin/phpunit ../modules/custom/sports/tests/src/Kernel/TeamCleanerTest.php  

And that is a very simple example of using Kernel tests for testing a component, particularly one that integrates with the database. We could have used a Functional test as well but that would have been overkill—it would run slower and make no use of the benefits that it offers over Kernel testing, such as browser integration.