A kernel test class builds its fixture again for every test method. The new #[ShareEnvironment] attribute (Drupal\TestTools\Attribute\ShareEnvironment) allows to opt into this new mode, letting Kernel tests build the environment once and share it among test methods. A class without the attribute keeps the old behavior in Drupal 12. The goal is to flip the default behavior in Drupal 13.
A pair of new methods are now available to override:
- The
::setUpEnvironment()method runs just once per test class and allows to perform all the setup tasks required by the test class as a whole. Before, these tasks were typically performed in the::setUp()method, which is still available for any setup task needing to run for each test method. - The
::resetEnvironment()method allows to perform cleanup tasks before the next test method runs.
Every test method still runs in its own process, so properties assigned in ::setUpEnvironment() are reset every time. Any data shared among test methods need to be loaded from the database. Only database state is shared. The site directory belongs to the test method.
Guidelines for test methods sharing the environment:
- a test method should not assume it is starting from a pristine database
- it should not assert on absolute identifiers or row counts
- it should read identifiers from the entities under test
- it should not drop or change any table it did not create
- the
::setUpEnvironment()method should be deterministic - test methods should be able to run in any order without making assumptions on what happened before
If a test method cannot respect the guidelines above and requires a dedicated environment to work correctly, it can use the attribute with a FALSE parameter to mark itself as requiring a dedicated environment explicitly.
Before
#[RunTestsInSeparateProcesses]
class MyKernelTest extends KernelTestBase {
protected static $modules = ['node'];
protected EntityStorageInterface $nodeStorage;
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('node');
$this->installConfig(['node']);
$this->nodeStorage = $this->container->get('entity_type.manager')->getStorage('node');
}
public function testNodeIsSaved(): void {
$node = $this->nodeStorage->create(['type' => 'page', 'title' => 'Test']);
$node->save();
$this->assertSame(1, (int) $node->id());
}
}
After
#[RunTestsInSeparateProcesses]
#[ShareEnvironment]
class MyKernelTest extends KernelTestBase {
protected static $modules = ['node'];
protected EntityStorageInterface $nodeStorage;
protected function setUpEnvironment(): void {
parent::setUpEnvironment();
$this->installEntitySchema('node');
$this->installConfig(['node']);
}
protected function setUp(): void {
parent::setUp();
$this->nodeStorage = $this->container->get('entity_type.manager')->getStorage('node');
}
public function testNodeIsSaved(): void {
$node = $this->nodeStorage->create(['type' => 'page', 'title' => 'Test']);
$node->save();
$this->assertNotNull($this->nodeStorage->load($node->id()));
}
}
A class that needs its own environment states it:
#[ShareEnvironment(FALSE)]
class MySchemaTest extends KernelTestBase {