From graft
Jenkins plugin testing expertise — JenkinsRule, RealJenkinsRule, JenkinsSessionRule, Pipeline testing, config roundtrips, Acceptance Test Harness page objects, and expert-approved test patterns. Use this skill when writing tests for Jenkins plugins, choosing between test rules, setting up test dependencies, or understanding Jenkins-specific test utilities. Make sure to use this skill whenever the user mentions Jenkins plugin tests, config roundtrip, Pipeline test, snippetizer test, or Jenkins test harness — even if they just say "add tests for my plugin." Triggers on: JenkinsRule, RealJenkinsRule, JenkinsSessionRule, Jenkins plugin test, config roundtrip, WorkflowJob test, acceptance test harness, ATH, @WithoutJenkins, BuildWatcher, LoggerRule, jenkins-test-harness, mvn test Jenkins, HtmlUnit Jenkins.
How this skill is triggered — by the user, by Claude, or both
Slash command
/graft:jenkins-testingThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Testing Jenkins plugins requires specialized test harnesses that spin up real Jenkins instances.
Testing Jenkins plugins requires specialized test harnesses that spin up real Jenkins instances.
The parent POM includes jenkins-test-harness automatically — no explicit dependency needed.
| Rule | Speed | Realism | Use when |
|---|---|---|---|
JenkinsRule | Fast | Good | Default choice. In-process Jenkins with HtmlUnit. |
RealJenkinsRule | Slow | Best | Classloader isolation, restart testing, FIPS mode. |
JenkinsSessionRule | Medium | Good | Persistence across restarts (same JENKINS_HOME). |
@WithoutJenkins | Fastest | None | Pure unit tests that don't need Jenkins. |
Decision flow:
@WithoutJenkinsClass.forName)? → RealJenkinsRuleJenkinsSessionRuleJenkinsRuleThe BOM handles version alignment. Add these in test scope:
<!-- Pipeline testing -->
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
<scope>test</scope>
</dependency>
<!-- Snippetizer testing -->
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Verifies configuration survives form submission → serialization → deserialization:
@Rule public JenkinsRule j = new JenkinsRule();
@Test
public void configRoundtrip() throws Exception {
FreeStyleProject p = j.createFreeStyleProject();
MyBuilder before = new MyBuilder("hello");
before.setTimeout(30);
p.getBuildersList().add(before);
j.configRoundtrip(p);
MyBuilder after = p.getBuildersList().get(MyBuilder.class);
j.assertEqualDataBoundBeans(before, after);
}
@Test
public void globalConfigRoundtrip() throws Exception {
MyConfig config = GlobalConfiguration.all().get(MyConfig.class);
config.setServerUrl("https://example.com");
j.configRoundtrip();
assertEquals("https://example.com", config.getServerUrl());
}
Write one for every @DataBoundConstructor/@DataBoundSetter field. This catches
serialization bugs, form binding mismatches, and XStream configuration errors.
@ClassRule public static BuildWatcher bw = new BuildWatcher();
@Rule public JenkinsRule j = new JenkinsRule();
@Test
public void pipelineSmokes() throws Exception {
WorkflowJob p = j.createProject(WorkflowJob.class, "test");
p.setDefinition(new CpsFlowDefinition(
"node { myStep name: 'test' }", true)); // true = sandbox
WorkflowRun b = j.buildAndAssertSuccess(p);
j.assertLogContains("expected output", b);
}
Load scripts from resources (exemplar pattern from cache-step-plugin):
p.setDefinition(new CpsFlowDefinition(
IOUtils.toString(getClass().getResource("testScript.groovy"), UTF_8), true));
Verifies Pipeline DSL generation round-trips correctly:
@Test
public void snippetizer() throws Exception {
SnippetizerTester st = new SnippetizerTester(j);
st.assertRoundTrip(new MyStep("value"), "myStep 'value'");
// Test with optional param
MyStep withExcludes = new MyStep("value");
withExcludes.setExcludes("*.tmp");
st.assertRoundTrip(withExcludes, "myStep excludes: '*.tmp', name: 'value'");
}
@Test
public void formValidationEscapesHtml() throws Exception {
FreeStyleProject p = j.createFreeStyleProject();
p.setDisplayName("<img src=x>");
// Verify the validation output escapes HTML
// (assertion depends on what you're testing)
}
@Test
public void permissionCheckInValidation() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
.grant(Jenkins.READ).onRoot().to("reader"));
try (ACLContext ctx = ACL.as(User.getById("reader", true))) {
FormValidation result = descriptor.doCheckName("test");
assertEquals(FormValidation.Kind.OK, result.kind);
}
}
mvn test # All tests
mvn test -Dtest=MyTest # Single class
mvn test -Dtest=MyTest#myMethod # Single method
mvn -Djenkins.test.timeout=300 verify # Custom timeout (seconds)
For detailed API documentation on test rules and advanced patterns, read:
references/test-rules.md — JenkinsRule, RealJenkinsRule, JenkinsSessionRule, LoggerRule APIreferences/test-patterns.md — CasC testing, ATH page objects, anti-patternsThread.sleep() — use waitForCompletion(), waitForMessage(), waitOnline()RealJenkinsRule for anything with reflectionj.getURL() or j.jenkins.getRootUrl()JenkinsSessionRulenpx claudepluginhub aneveux/claude-garden --plugin graftImplements, configures, and debugs JUnit extensions including custom extensions, rules, and conditional test execution in Java projects.
Generates declarative, scripted Jenkinsfiles and shared libraries for CI/CD pipelines with Docker/K8s agents, parallel stages, approvals, and security scans.
Guides Pytest plugin ecosystem including pytest-cov, pytest-mock usage and custom plugin development for Python testing projects.