"value":"\n <p>In <a href=\"https:\/\/www.oliverdavies.uk\/daily\/2022\/09\/14\/simpletest-drupal-test\">Wednesday's email<\/a>, I showed how quick it is to get started writing automated tests for a new Drupal module, starting with a functional test.<\/p>\n\n<p>I prefer the outside-in style (or London approach) of test-driven development, where I start with a the highest-level test that I can for a task. If the task needs me to make a HTTP request, then I\u2019ll use a functional test. If not, I\u2019ll use a kernel (or integration) test.<\/p>\n\n<p>I find that these higher-level types of tests are easier and quicker to set up compared to starting with lower-level unit tests, cover more functionality, and make it easier to refactor.<\/p>\n\n<h2 id=\"an-example\">An example<\/h2>\n\n<p>For example, this <code>Device<\/code> class which is a data transfer object around Drupal's <code>NodeInterface<\/code>. It ensures that the correct type of node is provided, and includes a named constructor and a helper method to retrieve a device's asset ID from a field:<\/p>\n\n<pre><code class=\"language-php\">final class Device {\n\n private NodeInterface $node;\n\n public function __construct(NodeInterface $node) {\n if ($node->bundle() != 'device') {\n throw new \\InvalidArgumentException();\n }\n\n $this->node = $node;\n }\n\n public function getAssetId(): string {\n return $this->node->get('field_asset_id')->getString();\n }\n\n public static function fromNode(NodeInterface $node): self {\n return new self($node);\n }\n\n}\n<\/code><\/pre>\n\n<h2 id=\"testing-getting-the-asset-id-using-a-unit-test\">Testing getting the asset ID using a unit test<\/h2>\n\n<p>As the <code>Node::create()<\/code> method (what I'd normally use to create a node) interacts with the database, I need to create a mock node to wrap with my DTO.<\/p>\n\n<p>I need to specify what value is returned from the <code>bundle()<\/code> method as well as getting the asset ID field value.<\/p>\n\n<p>I need to mock the <code>get()<\/code> method and specify the field name that I'm getting the value for, which also returns it's own mock for <code>FieldItemListInterface<\/code> with a value set for the <code>getString()<\/code> method.<\/p>\n\n<pre><code class=\"language-php\">\/** @test *\/\npublic function should_return_an_asset_id(): void {\n \/\/ Arrange.\n $fieldItemList = $this->createMock(FieldItemListInterface::class);\n\n $fieldItemList\n ->method('getString')\n ->willReturn('ABC');\n\n $deviceNode = $this->createMock(NodeInterface::class);\n\n $deviceNode\n ->method('bundle')\n ->willReturn('device');\n\n $deviceNode\n ->method('get')\n ->with('field_asset_id')\n ->willReturn($fieldItemList);\n\n \/\/ Act.\n $device = Device::fromNode($deviceNode);\n\n \/\/ Assert.\n self::assertSame('ABC', $device->getAssetId());\n}\n<\/code><\/pre>\n\n<p>This is quite a long 'arrange' section for this test, and just be confusing for those new to automated testing.<\/p>\n\n<p>If I was to refactor from using the <code>get()<\/code> and <code>getString()<\/code> methods to a different implementation, it's likely that the test would fail.<\/p>\n\n<h2 id=\"refactoring-to-a-kernel-test\">Refactoring to a kernel test<\/h2>\n\n<p>This is how I could write the same test using a kernel (integration) test:<\/p>\n\n<pre><code class=\"language-php\">\/**@test*\/\npublicfunctionshould_return_an_asset_id():void{\n\/\/Arrange.\n$node=Node::create([\n'field_asset_id'=>'ABC',\n'type'=>'device'\n]);\n\n\/\/Assert.\nself::assertSame('ABC',Device::fromNode($node)->getAssetId());\n}\n<\/code><\/pre>\n\n<p>Icancreateareal<code>Node<\/code>object,passthattothe<code>Device<\/code>DTO,andcallthe<code>getAssetId()<\/code>method.<\/p>\n\n<p>AsIcaninteractwiththedatabase,there'snoneedtocreatemocksordefinereturnvalues.<\/p>\n\n<p>The'arrange'stepismuchsmaller,andIthinkthatthisiseasiertoreadand
"format":"full_html",
"processed":"\n <p>In <a href=\"https:\/\/www.oliverdavies.uk\/daily\/2022\/09\/14\/simpletest-drupal-test\">Wednesday's email<\/a>, I showed how quick it is to get started writing automated tests for a new Drupal module, starting with a functional test.<\/p>\n\n<p>I prefer the outside-in style (or London approach) of test-driven development, where I start with a the highest-level test that I can for a task. If the task needs me to make a HTTP request, then I\u2019ll use a functional test. If not, I\u2019ll use a kernel (or integration) test.<\/p>\n\n<p>I find that these higher-level types of tests are easier and quicker to set up compared to starting with lower-level unit tests, cover more functionality, and make it easier to refactor.<\/p>\n\n<h2 id=\"an-example\">An example<\/h2>\n\n<p>For example, this <code>Device<\/code> class which is a data transfer object around Drupal's <code>NodeInterface<\/code>. It ensures that the correct type of node is provided, and includes a named constructor and a helper method to retrieve a device's asset ID from a field:<\/p>\n\n<pre><code class=\"language-php\">final class Device {\n\n private NodeInterface $node;\n\n public function __construct(NodeInterface $node) {\n if ($node->bundle() != 'device') {\n throw new \\InvalidArgumentException();\n }\n\n $this->node = $node;\n }\n\n public function getAssetId(): string {\n return $this->node->get('field_asset_id')->getString();\n }\n\n public static function fromNode(NodeInterface $node): self {\n return new self($node);\n }\n\n}\n<\/code><\/pre>\n\n<h2 id=\"testing-getting-the-asset-id-using-a-unit-test\">Testing getting the asset ID using a unit test<\/h2>\n\n<p>As the <code>Node::create()<\/code> method (what I'd normally use to create a node) interacts with the database, I need to create a mock node to wrap with my DTO.<\/p>\n\n<p>I need to specify what value is returned from the <code>bundle()<\/code> method as well as getting the asset ID field value.<\/p>\n\n<p>I need to mock the <code>get()<\/code> method and specify the field name that I'm getting the value for, which also returns it's own mock for <code>FieldItemListInterface<\/code> with a value set for the <code>getString()<\/code> method.<\/p>\n\n<pre><code class=\"language-php\">\/** @test *\/\npublic function should_return_an_asset_id(): void {\n \/\/ Arrange.\n $fieldItemList = $this->createMock(FieldItemListInterface::class);\n\n $fieldItemList\n ->method('getString')\n ->willReturn('ABC');\n\n $deviceNode = $this->createMock(NodeInterface::class);\n\n $deviceNode\n ->method('bundle')\n ->willReturn('device');\n\n $deviceNode\n ->method('get')\n ->with('field_asset_id')\n ->willReturn($fieldItemList);\n\n \/\/ Act.\n $device = Device::fromNode($deviceNode);\n\n \/\/ Assert.\n self::assertSame('ABC', $device->getAssetId());\n}\n<\/code><\/pre>\n\n<p>This is quite a long 'arrange' section for this test, and just be confusing for those new to automated testing.<\/p>\n\n<p>If I was to refactor from using the <code>get()<\/code> and <code>getString()<\/code> methods to a different implementation, it's likely that the test would fail.<\/p>\n\n<h2 id=\"refactoring-to-a-kernel-test\">Refactoring to a kernel test<\/h2>\n\n<p>This is how I could write the same test using a kernel (integration) test:<\/p>\n\n<pre><code class=\"language-php\">\/**@test*\/\npublicfunctionshould_return_an_asset_id():void{\n\/\/Arrange.\n$node=Node::create([\n'field_asset_id'=>'ABC',\n'type'=>'device'\n]);\n\n\/\/Assert.\nself::assertSame('ABC',Device::fromNode($node)->getAssetId());\n}\n<\/code><\/pre>\n\n<p>Icancreateareal<code>Node<\/code>object,passthattothe<code>Device<\/code>DTO,andcallthe<code>getAssetId()<\/code>method.<\/p>\n\n<p>AsIcaninteractwiththedatabase,there'snoneedtocreatemocksordefinereturnvalues.<\/p>\n\n<p>The'arrange'stepismuchsmaller,andIthinkthatthisiseasiertoread