-
Gerd Aschemann authored
-> planning#654
Gerd Aschemann authored-> planning#654
BDD with Cucumber
Introduction
Starting with Epic-654 (Bidirektionale Kommunikation in .NET- und Java-SDKs), we tried to define formal acceptance criteria with Gherkin. Gherkin is a so-called BDD language (Behaviour Driven Design), i.e., it allows to specify behaviour using a semiformal approach of mixing keywords with English (or other) language fragments.
Example:
Scenario: Optional callback-URL is used upon a new submission
Given a sender created a sender client
And the sender creates a new submission
And used a callback-URL with secret
And sets FIT-Connect as reply-channel
When the sender submits the new submission
Then the submission contains the callback-URL
And the submission contains the secret
And FIT-Connect is set as reply-channel
Each statement can then be implemented as a so-called test step in Java (or other languages) using frameworks like Cucumber (for Java), or SpecFlow (for .NET/C#).
The implementation of a step might look like this:
@And("the submission contains the secret")
public void theSubmissionContainsTheSecret() {
assertThat(createSubmission.getCallback().getSecret(), is(CALLBACK_SECRET));
}
Here we make sure that the submitted metadata (i.e., the payload to a put request) contains the desired reply channel. We do not test getters/setters of Java objects, but the logic of the SDK itself, without making a call to the service itself (using some mock objects).
Test flow
Normal Integration Tests
The integration tests implemented so far, always perform a round trip from the test suite via the SDK to the submission service. Therefore, they can only indirectly check whether the implemented calls had correct payloads.
BDD Integration Tests
The BDD based tests should not require a running submission service. Nevertheless, we would like to test sent data by intercepting the backend calls with mock objects. Then it is possible to test the behaviour of the SDK itself by validating the HTTP payload which was handed over to the HTTP Client.
An implementation of such a mock interception looks like this:
when(httpClientMock.post(anyString(), anyMap(),
any(CreateSubmission.class), eq(CreatedSubmission.class))) (1)
.thenAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
createSubmission
= invocation.getArgument(2); (2)
return (new HttpResponse<CreatedSubmission>(200, createdSubmission));
}
});
1 | When the post request to create a new submission is executed |
2 | We store the create object to verify later whether it contained the correct data, cf. Java implementation of a particular test step
|
Caveats
The current implementation contains two challenges with the used version of PowerMock which need bo be addressed in the future.
-
PowerMock should support mocking of private methods. For some reason we could not make use of this feature but had to make the respective calls
protected
(cf. respective TODOs in the source ofClientFactory
). -
PowerMock only works with JUnit 4 so far. There is a JUnit 5 extension prepared already, cf. powermock/pull/1146.
For a local build it is currently recommended to check out/clone https://github.com/ascheman/powermock/tree/junit-jupiter-extension.
Running
./gradlew publishToMavenLocal
will install the proper version (2.0.10).