Skip to main content

Testing Plugin Steps

Step definitions should be thoroughly tested because they will likely be called by multiple Cycle scenarios. If a step has defects, then it could destabilize entire test suites. Thankfully, testing steps is straightforward. JUnit is the recommended test framework for Java plugins.

Unit tests

In most cases, unit tests are sufficient for testing step definitions. A unit test is a white-box test that covers the code directly and does not have dependencies on any external systems (like databases, APIs, filesystems, or other plugins). Below is an example unit test for the VerifyCounterStep step definition class from a previous example:

public class VerifyCounterStepTest {

private SuiteContext suiteContext;
private ScenarioContext scenarioContext;
private VerifyCounterStep step;

@BeforeEach
public void setUp() {
// Set up fake data for scenario and suite contexts.
suiteContext = new SuiteContext(null, null, new SuiteState());
scenarioContext = new ScenarioContext(new ScenarioState(), UUID.randomUUID());
step = new VerifyCounterStep();
}

@Test
public void call_PASS() {
scenarioContext.getScenarioState().set(CounterConstants.KEY_COUNTER, 5);
StepInputsBody rawInputs = new StepInputsBody().putParametersItem("total", 5);
StepInputs inputs = new StepInputs(rawInputs);
StepResponse response = step.call(suiteContext, scenarioContext, inputs);
assertEquals(ExecutionStatus.PASS, response.getStatus());
assertEquals("The counter value is 5.", response.getMessage());
}

@Test
public void call_FAIL() {
scenarioContext.getScenarioState().set(CounterConstants.KEY_COUNTER, 5);
StepInputsBody rawInputs = new StepInputsBody().putParametersItem("total", 6);
StepInputs inputs = new StepInputs(rawInputs);
StepResponse response = step.call(suiteContext, scenarioContext, inputs);
assertEquals(ExecutionStatus.FAIL, response.getStatus());
assertEquals("The counter value should be 6, but it is actually 5.", response.getMessage());
}

}

Integration tests

Sometimes, steps interact with other systems and need integration tests to verify that the connections between them work correctly. Integration tests are more intense because they require setup for the dependencies. For example, the WebDriver plugin has several integration tests that bring up a Selenium WebDriver instance with a browser session.

Integration test classes should be annotated with SpringBootTest because they need the full plugin to be up and running. The step definition class under test should also be auto-wired so the correct instance is used for testing. You might need to auto-wire other parts as well, such as if you have any service classes. The test class should look like this:

@SpringBootTest
public class MyStepIntegrationTest {

@Autowired
private MyStep step;

// Put test methods here.
// ...
}

End-to-end tests

Finally, it is beneficial to test that a plugin's steps actually work when run from a CycleScript feature file. To do this, you will need to build the plugin, plug it into Cycle, and run feature files that call the steps. The feature files can be basic: they don't need to run full tests; they merely need to verify that the steps behave as expected.