uuid: - value: 323bc6bc-069b-497b-9f64-d64c21bdba79 langcode: - value: en type: - target_id: daily_email target_type: node_type target_uuid: 8bde1f2f-eef9-4f2d-ae9c-96921f8193d7 revision_timestamp: - value: '2025-05-11T09:00:20+00:00' revision_uid: - target_type: user target_uuid: b8966985-d4b2-42a7-a319-2e94ccfbb849 revision_log: { } status: - value: true uid: - target_type: user target_uuid: b8966985-d4b2-42a7-a319-2e94ccfbb849 title: - value: 'Keep logic within tests for as long as you can' created: - value: '2024-02-16T00:00:00+00:00' changed: - value: '2025-05-11T09:00:20+00:00' promote: - value: false sticky: - value: false default_langcode: - value: true revision_translation_affected: - value: true path: - alias: /daily/2024/02/16/keep-logic-within-tests-for-as-long-as-you-can langcode: en body: - value: |

Inspired by some recent podcast guests, I've started writing the first code for a Drupal-based SaaS product that I've been thinking of creating.

Here's an early iteration of the first test I wrote:

public function test_it_creates_a_project_node_from_json(): void {
        self::assertNull(Node::load(id: 1));

        $this->installEntitySchema(entity_type_id: 'node');
        $this->installConfig(modules: self::$modules);

        $projectData = json_decode(json: self::$projectJson, associative: TRUE);
        self::assertNotNull($projectData);

        Node::create([
          'title' => $projectData['list'][0]['title'],
          'type' => 'drupal_project',
        ])->save();

        $node = Node::load(id: 1);

        self::assertNotNull($node);
        self::assertInstanceOf(actual: $node, expected: NodeInterface::class);
        self::assertSame(actual: $node->label(), expected: 'Override Node Options');

        self::assertSame(
          actual: $node->get('field_drupalorg_node_id')->getString(),
          expected: strval(107871),
        );
      }
      

It checks that, given some defined JSON data, it will create a node in my database.

It confirms no node ID exists when starting, runs some setup setups (this is a Kernel test), decodes the JSON, creates the node and asserts it contains the expected values.

There are two things that you may be wondering...

The answer to both is that this is the first test, and I want to write as little code as possible for it to pass.

When I write the second test, I'll either need to duplicate the setup lines or extract them to a setUp() method.

I'll also need to refactor the code that creates the node.

Once I've written the second test, to get it to pass, I refactored to use Repository, Builder and Action classes.

If there's a regression, the test I had will fail, and I could revert to the passing version before reattempting the refactor.

With test-driven development, I want to work in small and simple steps and get to green by making the smallest and easiest possible change.

When I have a test that forces me to refactor and adopt a more complex approach, I'll do it.

format: full_html processed: |

Inspired by some recent podcast guests, I've started writing the first code for a Drupal-based SaaS product that I've been thinking of creating.

Here's an early iteration of the first test I wrote:

public function test_it_creates_a_project_node_from_json(): void {
        self::assertNull(Node::load(id: 1));

        $this->installEntitySchema(entity_type_id: 'node');
        $this->installConfig(modules: self::$modules);

        $projectData = json_decode(json: self::$projectJson, associative: TRUE);
        self::assertNotNull($projectData);

        Node::create([
          'title' => $projectData['list'][0]['title'],
          'type' => 'drupal_project',
        ])->save();

        $node = Node::load(id: 1);

        self::assertNotNull($node);
        self::assertInstanceOf(actual: $node, expected: NodeInterface::class);
        self::assertSame(actual: $node->label(), expected: 'Override Node Options');

        self::assertSame(
          actual: $node->get('field_drupalorg_node_id')->getString(),
          expected: strval(107871),
        );
      }
      

It checks that, given some defined JSON data, it will create a node in my database.

It confirms no node ID exists when starting, runs some setup setups (this is a Kernel test), decodes the JSON, creates the node and asserts it contains the expected values.

There are two things that you may be wondering...

The answer to both is that this is the first test, and I want to write as little code as possible for it to pass.

When I write the second test, I'll either need to duplicate the setup lines or extract them to a setUp() method.

I'll also need to refactor the code that creates the node.

Once I've written the second test, to get it to pass, I refactored to use Repository, Builder and Action classes.

If there's a regression, the test I had will fail, and I could revert to the passing version before reattempting the refactor.

With test-driven development, I want to work in small and simple steps and get to green by making the smallest and easiest possible change.

When I have a test that forces me to refactor and adopt a more complex approach, I'll do it.

summary: null field_daily_email_cta: { }