AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Drupal Kernel Test

skill-trebormc-drupal-ai-agents-drupal-kernel-test · by trebormc

>-

No reviews yet
0 installs
9 views
0.0% view→install

Install

$ agentstack add skill-trebormc-drupal-ai-agents-drupal-kernel-test

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-trebormc-drupal-ai-agents-drupal-kernel-test)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Drupal Kernel Test? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Drupal Kernel Test

What It Is

A Kernel test partially boots the Drupal kernel: service container, database (SQLite by default), entity system, configuration and hooks. There is NO web server or browser.

Speed: 1-10 seconds per test (vs 10-120s for Functional).

This is the default test for custom modules. If in doubt between Kernel and Functional, choose Kernel. Only upgrade to Functional when you need to verify rendered HTML output.

When to Use

  • Custom services that use entity storage, database, config, or the container
  • Entity CRUD (create, read, update, delete)
  • Database queries (entity queries, select queries)
  • Access logic and permissions (without verifying UI)
  • Plugin managers with real discovery
  • Event subscribers
  • Hook implementations
  • Token replacement
  • Migrations (migrate API)
  • Field types, formatters, widgets (logic, not rendering)
  • Form submit/validate handlers (handler logic, not the rendered form)
  • Queue workers
  • Cron hooks

When NOT to Use

  • Need to verify rendered HTML -> Functional
  • Need to submit forms via UI -> Functional
  • Need JavaScript -> FunctionalJavascript
  • Pure PHP logic without Drupal dependencies -> Unit

Base Template

installEntitySchema('user');
    $this->installConfig(['system', 'MODULE']);
  }

  public function testSomething(): void {
    $service = $this->container->get('MODULE.my_service');
    // assertions...
  }

}

Setup Methods -- What to Use for What

installEntitySchema('entitytypeid')

Installs DB tables for a content entity. Required before doing CRUD with that entity. DO NOT use for config entities (they have no tables).

$this->installEntitySchema('user');
$this->installEntitySchema('node');
$this->installEntitySchema('taxonomy_term');

installConfig(['module_name'])

Imports default config (config/install/ and config/optional/) from modules. Needed when your code reads configuration.

$this->installConfig(['system', 'node', 'filter', 'my_module']);

installSchema('module', ['table'])

Installs tables defined in hook_schema(). Only for custom tables, not for entities.

$this->installSchema('my_module', ['my_module_tracking']);

Container Access

$entityTypeManager = $this->container->get('entity_type.manager');
$configFactory = $this->container->get('config.factory');
$myService = $this->container->get('my_module.calculator');

Pattern: Custom Service Test

installEntitySchema('user');
    $this->installEntitySchema('node');
    $this->installConfig(['system', 'node', 'filter', 'my_module']);

    NodeType::create(['type' => 'article', 'name' => 'Article'])->save();
    $this->analyzer = $this->container->get('my_module.article_analyzer');
  }

  /**
   * @covers ::analyze
   */
  public function testAnalyzePublishedArticle(): void {
    $node = Node::create([
      'type' => 'article',
      'title' => 'Test Article',
      'status' => 1,
    ]);
    $node->save();

    $result = $this->analyzer->analyze($node);

    $this->assertSame('published', $result->getStatus());
    $this->assertGreaterThan(0, $result->getWordCount());
  }

  /**
   * @covers ::analyze
   */
  public function testAnalyzeThrowsOnInvalidBundle(): void {
    $this->expectException(\InvalidArgumentException::class);

    NodeType::create(['type' => 'page', 'name' => 'Page'])->save();
    $node = Node::create(['type' => 'page', 'title' => 'Not article']);
    $node->save();

    $this->analyzer->analyze($node);
  }

}

Pattern: Entity CRUD Test

public function testCreateAndLoadEntity(): void {
  $node = Node::create([
    'type' => 'article',
    'title' => 'My article',
    'status' => 0,
  ]);
  $node->save();

  // Reload from DB to verify real persistence
  $loaded = Node::load($node->id());
  $this->assertNotNull($loaded);
  $this->assertSame('My article', $loaded->getTitle());
  $this->assertFalse((bool) $loaded->isPublished());
}

public function testUpdateEntity(): void {
  $node = Node::create(['type' => 'article', 'title' => 'Original']);
  $node->save();

  $node->setTitle('Updated');
  $node->save();

  $loaded = Node::load($node->id());
  $this->assertSame('Updated', $loaded->getTitle());
}

public function testDeleteEntity(): void {
  $node = Node::create(['type' => 'article', 'title' => 'To delete']);
  $node->save();
  $nid = $node->id();

  $node->delete();
  $this->assertNull(Node::load($nid));
}

Pattern: Access and Permissions Test

use Drupal\user\Entity\User;
use Drupal\user\Entity\Role;

public function testAccessCheck(): void {
  $user_without_permission = User::create(['name' => 'no_access', 'status' => 1]);
  $user_without_permission->save();

  $role = Role::create([
    'id' => 'my_role',
    'label' => 'My Role',
  ]);
  $role->grantPermission('access my_module reports');
  $role->save();

  $user_with_permission = User::create(['name' => 'with_access', 'status' => 1]);
  $user_with_permission->addRole('my_role');
  $user_with_permission->save();

  $checker = $this->container->get('my_module.access_checker');
  $this->assertFalse($checker->canViewReports($user_without_permission));
  $this->assertTrue($checker->canViewReports($user_with_permission));
}

Pattern: Configuration Test

public function testDefaultConfig(): void {
  $config = $this->config('my_module.settings');
  $this->assertSame(10, $config->get('max_items'));
  $this->assertTrue($config->get('cache_enabled'));
}

public function testConfigChange(): void {
  $config = $this->config('my_module.settings');
  $config->set('max_items', 50)->save();

  $service = $this->container->get('my_module.listing');
  $this->assertSame(50, $service->getMaxItems());
}

Pattern: Event Subscriber Test

public function testEventSubscriber(): void {
  $node = Node::create(['type' => 'article', 'title' => 'Test', 'status' => 1]);
  $node->save();

  $event = new ArticlePublishedEvent($node);
  $dispatcher = $this->container->get('event_dispatcher');
  $dispatcher->dispatch($event, ArticlePublishedEvent::EVENT_NAME);

  $this->assertTrue($event->wasProcessed());
}

Pattern: Auxiliary Test Module

When you need routes, services, or config that only exist for the test:

# tests/modules/my_module_test/my_module_test.info.yml
name: 'My Module Test'
type: module
core_version_requirement: ^10 || ^11
package: Testing
dependencies:
  - my_module:my_module
hidden: true

In the test:

protected static $modules = ['my_module', 'my_module_test'];

Useful Core Traits

use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\user\Traits\UserCreationTrait;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\Traits\Core\CronRunTrait;

class MyTest extends KernelTestBase {
  use NodeCreationTrait;
  use UserCreationTrait;
  use ContentTypeCreationTrait;
  use CronRunTrait;
}

Anti-Patterns

  1. Do not install unnecessary modules in $modules. Each one adds time.
  2. Do not use installEntitySchema() for config entities. They have no tables.
  3. Do not use enableModules() in setUp(). Use the $modules property.
  4. Do not make assertions about rendered HTML. That is a Functional test.
  5. Do not create unnecessary fixtures. Only what the test needs.
  6. Do not forget to reload entities. After modifying, use Entity::load($id) to verify persisted state.

Running Tests

First pick the config form ONCE per session: ssh web test -f phpunit.xml && echo "ROOT" || echo "CORE"

# Form ROOT (project phpunit.xml exists — it already sets SIMPLETEST_DB):
ssh web ./vendor/bin/phpunit $DDEV_DOCROOT/modules/custom/MODULE/tests/src/Kernel
ssh web ./vendor/bin/phpunit --filter testName $DDEV_DOCROOT/modules/custom/MODULE/tests/src/Kernel

# Form CORE (no project phpunit.xml — pass env vars explicitly):
ssh web env SIMPLETEST_DB=mysql://db:db@db/db SIMPLETEST_BASE_URL=http://localhost \
  ./vendor/bin/phpunit -c $DDEV_DOCROOT/core $DDEV_DOCROOT/modules/custom/MODULE/tests/src/Kernel

Never use -c core alone and never rely on --testsuite — see the drupal-testing rule for the full canonical pattern. Do not export env vars in the agent container (they would not reach the web container via SSH) — pass them inline with env as shown.

Troubleshooting

| Error | Cause | Fix | |-------|-------|-----| | "Unknown entity type X" | Schema not installed or module missing | Add $this->installEntitySchema('X') in setUp() AND the providing module to $modules | | "Base table or view not found" | Missing schema install | Add the matching installSchema() / installEntitySchema() call in setUp() | | "Service not found" | Providing module not enabled | Add the module that defines the service to $modules | | Class not found | Stale autoloader or wrong namespace | ssh web composer dump-autoload; verify namespace matches directory path | | "Could not connect to database" | SIMPLETEST_DB not set | Use Form CORE with explicit env vars (above) |

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.