Search code examples
javacucumbercucumber-jvmcucumber-javacitrus-framework

Asynchronous steps execution with Cucumber (and/or Citrus)


Suppose I have a test like below (using cucumber) -

Scenario: Login successfully to Facebook
  Given the user test exists
  And user name and password is entered
  When the login form is submitted
  Then I expose a HTTP-Rest service to validate the user name and password
  When I receive a validation success message
  Then display the welcome message to the user

Here, when "the login form is submitted" is called, it submit the request to a HTTP REST service which will pass the user name and password to another HTTP Rest Service (that would be exposed by Citrus Framework) using "I expose a HTTP-Rest service to validate the user name and password" which will validate the data and send a success response. Therefore step definitions for "the login form is submitted" and "I expose a HTTP-Rest service to validate the user name and password" should be executed asynchronously.

Could you please help me - how I could achieve this using cucumber (or/and citrus).

Note: I'm not using any stub application to expose the HTTP Rest service for "I expose a HTTP-Rest service to validate the user name and password"; I'm trying to expose the service using Citrus framework.

Step definitions are written in java.


Solution

  • First of all you need to setup the citrus-cucumber extension in your project. Then you should be able to use @CitrusResource annotation that injects a test runner instance to your steps class:

    @CitrusResource
    private TestRunner runner;
    

    Also you can inject the http server instance that should receive the request.

    @CitrusEndpoint(name = "userServer")
    private HttpServer userServer;
    

    Then you can use test runner and the server to receive the request and send the response in a step definition:

    @Then("^I expose a HTTP-Rest service to validate the user name and password$")
    public void exposeHttpRestService() {
        runner.http(http -> http.server(userServer)
            .receive()
            .post()
            .payload("{\"username\": \"test\", \"password\": \"secret\"}"));
    
        runner.http(http -> http.server(userServer)
            .send()
            .response(HttpStatus.OK));
    }
    

    The login form should be submitted in a separate step definition using a separate thread in order to create asynchronous nature:

    @When("^the login form is submitted$")
    public void submitForm() {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.submit(() -> {
            // do submit the form
        });    
    }