These guides describe the current master build. Select a release in the API Reference for released APIs.
Getting Started
From zero to full server integration test.
Use this as your baseline setup for a Maven project that tests a plugin on real Paper/Spigot runtimes.
Prerequisites
- Java 21
- Maven 3.9+
- Linux, macOS, or a recent version of Windows with UDS support (Windows is untested, though)
1. Add framework dependency
These examples use JitPack coordinates. Add JitPack to both repositories and
pluginRepositories, as shown in the repository setup.
Set your lightkeeper.version Maven property to master-SNAPSHOT for these current-master guides.
Use the same version for the framework and Maven plugin. Locally installed Maven artifacts use
nl.pim16aap2.lightkeeper as the group ID instead.
<dependency>
<groupId>com.github.PimvanderLoos.LightKeeper</groupId>
<artifactId>lightkeeper-framework-junit</artifactId>
<version>${lightkeeper.version}</version>
<scope>test</scope>
</dependency>
2. Configure prepare + cleanup goals
The Maven plugin provisions its embedded runtime agent automatically. Your plugin under test must be
listed explicitly in plugins; it is not selected automatically from the current project.
<plugin>
<groupId>com.github.PimvanderLoos.LightKeeper</groupId>
<artifactId>lightkeeper-maven-plugin</artifactId>
<version>${lightkeeper.version}</version>
<executions>
<execution>
<id>prepare-server</id>
<goals><goal>prepare-server</goal></goals>
<configuration>
<serverType>paper</serverType>
<userAgent>LightKeeper/${project.version} (https://example.com/my-plugin)</userAgent>
<runtimeManifestPath>${project.build.directory}/lightkeeper/runtime-manifest.json</runtimeManifestPath>
<plugins>
<plugin>
<sourceType>path</sourceType>
<path>${project.build.directory}/${project.build.finalName}.jar</path>
</plugin>
</plugins>
</configuration>
</execution>
<execution>
<id>cleanup-server</id>
<phase>post-integration-test</phase>
<goals><goal>cleanup-server</goal></goals>
<configuration>
<deleteTargetServerOnSuccess>true</deleteTargetServerOnSuccess>
<failsafeSummaryPath>${project.build.directory}/failsafe-reports/failsafe-summary.xml</failsafeSummaryPath>
<serverWorkDirectoryRoot>${project.build.directory}/lightkeeper-server</serverWorkDirectoryRoot>
</configuration>
</execution>
</executions>
</plugin>
userAgent may be set in the plugin-level configuration, as a shared value,
or in an execution's configuration, as shown here. Execution-level values override shared
values with the same name. Both locations are valid; moving it does not require a LightKeeper version change.
Replace the example project URL with your own contact URL or email address.
The path above refers to the JAR built by this Maven module, normally
target/<artifactId>-<version>.jar. During mvn verify, Maven runs
package before LightKeeper's pre-integration-test preparation, which copies the JAR
into the test server's plugins/ directory. The file must exist when preparation runs.
If shading or another packaging step produces a separate deployable JAR, point path to that
output, including its classifier if applicable. Use the same JAR you would install on a normal server.
For a separate integration-test module, reference the plugin module's built JAR or use
sourceType=maven with its groupId, artifactId, and version.
The path above always refers to the module containing this configuration.
3. Pass runtime manifest to tests
Put this configuration in Maven Failsafe in the module containing the integration tests. Run integration
tests with mvn verify. For IDE gutter launches, use the IDE setup guide,
including its module-selection commands when running from a multi-module project root.
<systemPropertyVariables>
<lightkeeper.runtimeManifestPath>
${project.build.directory}/lightkeeper/runtime-manifest.json
</lightkeeper.runtimeManifestPath>
</systemPropertyVariables>
4. Write your first test
import nl.pim16aap2.lightkeeper.framework.ILightkeeperFramework;
import nl.pim16aap2.lightkeeper.framework.LightkeeperExtension;
import nl.pim16aap2.lightkeeper.framework.PlayerHandle;
import nl.pim16aap2.lightkeeper.framework.WorldHandle;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static nl.pim16aap2.lightkeeper.framework.assertions.LightkeeperAssertions.assertThat;
@ExtendWith(LightkeeperExtension.class)
class GettingStartedExample
{
@Test
void placeBlock_shouldUpdateWorld(ILightkeeperFramework framework)
{
// setup
final WorldHandle world = framework.worlds().main();
final PlayerHandle player = framework.bots().builder()
.withName("lk_tester")
.atSpawn(world)
.build();
// execute
player.placeBlock("minecraft:stone", 1, 100, 0).andWaitTicks(1);
// verify
assertThat(world).hasBlockAt(1, 100, 0).ofType("minecraft:stone");
}
}
Need full examples? See integration tests in lightkeeper-integration-tests.