4
votes

Consider the following cucumber scenario:-

Scenario: Test payment
 Given I login to terminal
 When POS token is generated asynchronously
 Then user generates mobile token
 And payment is successful

The step "POS token is generated asynchronously" needs to execute asynchronously and should not block the execution of downstream steps after it. I was able to get it done with FutureTask in Java. However in case of failures I am not able to assert the failures. Below is the code snippet

@When("^POS token is generated asynchronously$")
public void gs_Consumer() throws Throwable {

    HashMap<String, Object> m = DataContainer.getDataMap();

    ExecutorService executor = Executors.newFixedThreadPool(2);
    FutureTask<Object> futureTask1 = null;

    futureTask1 = new FutureTask<Object>(new Callable<Object>() {

        public Object call() throws Exception {

            DataContainer.setDataMap(m);

            try {
                retrieve_consumer_information();
            } catch (Throwable e) {
                DataContainer.getDataMap().put("exception", e);
                throw new Exception(e);
            }
            return null;
        }
    });

    executor.execute(futureTask1);

    DataContainer.getDataMap().put("response", futureTask1);
    // Shutdown the ExecutorService
    executor.shutdown();
}

Then I get the response in the After method since I cannot do a futureTask1.get() inside this method as it will block the execution from executing the other downstream steps.

public void afterAsynchMethod() {

     try {
        ((FutureTask<Object>) DataContainer.getDataMap().get("response")).get();
    } catch (InterruptedException | ExecutionException e) {
        // TODO Auto-generated catch block
        Assert.fail(e.getMessage());
    }

}

Now if the exception happens in the After method the scenario still is not reflected as a failed scenario. How do I fail the scenario in this case or any other ways of doing this?

1
We had very similar usecases when creating system integration tests using cucumber, therefore we created a small library that makes reacting to asynchronous events in tests much easier: github.com/zalando/switchboard - Jörn Horstmann
@JörnHorstmann your ghthub link is now a 404, can you check if the project has been moved elsewhere? - Eddy
@Eddy The original developer still has a fork in his github account at github.com/whiskeysierra/switchboard - It seems the project was not that interesting for a broader audience and so was removed to reduce clutter. - Jörn Horstmann

1 Answers

2
votes

This scenario has a lot of details in it. I would consider pushing the details down in the stack. Possible hide as many as I can in a helper class that the step will be using.

A possibility could be

Scenario: Thomas pays for a yearly support subscription
Given Thomas has payed 150 EUR with his credit card
When the payment is confirmed
Then he should get a receipt

That talks more about the expected behaviour rather than the implementation. Thomas doesn't care if the service is asynchronous or not.

But what about the implementation then? The implementation should care about the asynchronous nature of the problem. But not the scenario. The scenario should only describe the desired behaviour.

To me, it sounds like you are connecting to an external service. A service this program doesn't control. Could be a network call away.

I would create a stub that responds as the real service for a given call. The stub will respond immidiately and never have a broken network stopping it. This would remove the need for handling the asynchronous behaviour here.

I would then implement an integration test that calls the real service with the same argument as the stub was called. And expect the very same reasons from the external service as the stub is hard coded to respond. This would not be a business facing test and therefore not something I would describe using Gherkin. I would probably implement it using JUnit or similar testing framework.

This is perhaps a bit more work, but it would give a more reliable testing setup. And you could use the scenario described in Gherkin as a communication tool between development and the business stakeholders. The stakeholder probably doesn't care either if the payment is asynchronous or not. they care about the fact that Thomas can make a payment and gets a receipt.