Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add skills/trebormc/drupal-ai-agents/drupal-unit-testnpx skills add trebormc/drupal-ai-agents --skill drupal-unit-testgit clone --depth 1 https://github.com/trebormc/drupal-ai-agentsWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/trebormc/drupal-ai-agents/drupal-unit-test)<a href="https://agentmods.dev/skills/trebormc/drupal-ai-agents/drupal-unit-test"><img src="https://agentmods.dev/badge/skills/trebormc/drupal-ai-agents/drupal-unit-test.svg" alt="Measured on agentmods" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00136 | $0.02828 |
| Opus 5 | $0.00068 | $0.01414 |
| Sonnet 5 | $0.00027 | $0.00566 |
| Haiku 4.5 | $0.00014 | $0.00283 |
Grade A, and why
drupal-unit-test scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 3d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 302 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Environment
All commands via ssh web. Use $DDEV_DOCROOT for paths.
Detect test gaps: ssh web drush audit:run phpunit --filter="module:MODULE" --format=json
Drupal 10+11 Compatibility (CRITICAL)
Use PHPDoc annotations only — NEVER PHP 8 attributes. Drupal 10 = PHPUnit 9.x (no attribute support).
| Use THIS | NOT this |
|---|---|
@coversDefaultClass \My\Class |
#[CoversClass(MyClass::class)] |
@covers ::methodName |
#[Covers('methodName')] |
@group mymodule |
#[Group('mymodule')] |
@dataProvider providerName |
#[DataProvider('providerName')] |
Workflow
- Read source class in
src/ - Check existing tests in
tests/src/Unit/ - Generate test class following templates below
- Run test (Form ROOT — requires project phpunit.xml; if missing, use Form CORE from the drupal-testing skill):
ssh web ./vendor/bin/phpunit $DDEV_DOCROOT/modules/custom/MODULE/tests/src/Unit/Service/MyServiceTest.php - Run PHPCS — always try Audit module first:
# Preferred: Audit module (check if installed first) ssh web drush audit:run phpcs --filter="module:MODULE" --format=json # Fallback only if Audit module not installed: ssh web ./vendor/bin/phpcs --standard=Drupal,DrupalPractice $DDEV_DOCROOT/modules/custom/MODULE/tests/src/Unit/
File Structure & Namespace
$DDEV_DOCROOT/modules/custom/MODULE/tests/src/Unit/
├── Service/MyServiceTest.php # Drupal\Tests\MODULE\Unit\Service
├── Plugin/Block/MyBlockTest.php # Drupal\Tests\MODULE\Unit\Plugin\Block
├── Form/MyFormTest.php # Drupal\Tests\MODULE\Unit\Form
└── Controller/MyControllerTest.php # Drupal\Tests\MODULE\Unit\Controller
Template: Service Test (Complete Example)
<?php
declare(strict_types=1);
namespace Drupal\Tests\mymodule\Unit\Service;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\ImmutableConfig;
use Drupal\mymodule\Service\MyService;
use Drupal\Tests\UnitTestCase;
/**
* Tests the MyService class.
*
* @coversDefaultClass \Drupal\mymodule\Service\MyService
* @group mymodule
*/
class MyServiceTest extends UnitTestCase {
protected MyService $service;
protected ConfigFactoryInterface $configFactory;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->configFactory = $this->createMock(ConfigFactoryInterface::class);
$this->service = new MyService($this->configFactory);
}
/**
* @covers ::process
*/
public function testProcessValidInput(): void {
$config = $this->createMock(ImmutableConfig::class);
$config->method('get')->willReturn('value');
$this->configFactory->method('get')->willReturn($config);
$result = $this->service->process('test');
$this->assertIsArray($result);
$this->assertNotEmpty($result);
}
/**
* @covers ::process
* @dataProvider processDataProvider
*/
public function testProcessScenarios(string $input, bool $expectEmpty): void {
$config = $this->createMock(ImmutableConfig::class);
$config->method('get')->willReturn('default');
$this->configFactory->method('get')->willReturn($config);
$result = $this->service->process($input);
$this->assertEquals($expectEmpty, empty($result));
}
/**
* @return array
* Test scenarios.
*/
public static function processDataProvider(): array {
return [
'valid input' => ['valid', FALSE],
'another case' => ['other', FALSE],
];
}
}
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 3d ago First seen · 302 lines · 136 tokens per session scan A 7010a234d927
drupal-unit-test is a skill published in the GitHub repository trebormc/drupal-ai-agents (10 stars, last pushed 1mo ago), licensed Apache-2.0. It adds 136 tokens to every session and 2,828 once invoked, about $0.0007 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other skills, from other repositories
run-helix-tests
Submit and monitor .NET MAUI unit tests on Helix infrastructure. Supports running XAML, Resizetizer, Core, Essentials, and other unit test projects on distributed Helix queues.
write-tests
Write failing tests from requirements. Invoke for each todo before /implement.
dart-add-unit-test
Write and organize unit tests for functions, methods, and classes using package:test. Use when creating new logic or fixing bugs to ensure code remains correct and regression-free.
nunit-testing
Use when writing or modifying tests in NUnit's own test projects, or when making a behavioral change to production code that needs test coverage. Covers test structure, attribute choice, helper visibility, platform guards, and which test projects are real.
check-and-test
Run lint checks (ruff for Python, Biome for TS/JS), type checks (pyright for Python, tsc for TS/JS), and the standard pytest tiers (unit + e2e + tests skipped during pre-commit). Investigates failures to determine if they are application bugs or test issues, and fixes application bugs rather than weakening tests. Does…
mobiai-ios-testing
Use when writing or running tests in an iOS project — unit tests, UI tests, snapshot tests, choosing the right framework.