Given-When-Then: Dealing with pauses and timeouts

Gojko Adzic and the good people at SpecFlow published a series of posts on advanced topics in Given-When-Then scenario writing called Given-When-Then With Style: The Community Challenge. And, good news for us practitioners, the “community challenge” part means it's an all-skate! Each week's post describes a specific situation that some find difficult to express in scenarios. Anyone can propose a solution. The following week's post considers some of the proposals, describing drawbacks and benefits of each, and presenting a detailed exposition of a top solution. I highly recommend the series.

This week's Pauses and Timeouts challenge is on handling situations where there is a pause or timeout in the activity. I've dealt with many situations like this, and handled it in various ways in scenarios. In one case, a shopping checkout required payment processing which eventually delegated to external service provides. In another example, an application queued report requests and notified the requestor to retrieve their report once it was ready. More recently, I worked with a system in which data modified in a mobile app was expected to appear for workers in a different role who were using a Web application to manage operations. As Adzic notes in the Pauses and Timeouts challenge, this situation “is symptomatic of working with an asynchronous process, often an external system or an executable outside of your immediate control.”

Here are a couple of approaches I've used.

Option 1: Raise the level of abstraction and ignore the pause

This has worked for me when my primary interest is verifying the human-observable result of an integrated system, and I'm less interested in verifying internal operations or hand offs. For this to work, characteristics that lead to success or failure have to be in the Background or Givens. Using the challenge's example of a checkout process with a risk evaluation, it might look something like:

Scenario: Successful Checkout
  Given an order in checkout
      And a shopper with a satisfactory risk profile
      And a valid form of payment
  When the shopper submits the order
  Then the shopper sees the advice that their payment has been accepted
      And the system has sent a payment capture request
      And the system has sent the shopper's order for fulfillment. 

Scenario: Unsuccessful Checkout - not authorized

  Given an order in checkout
      And a shopper with an UNsatisfactory risk profile
      And a valid form of payment
  When the shopper submits the order
  Then the shopper sees the advice that the system can't accept their order
      And the shopper's payment method is not charged

Scenario: Unsuccessful Checkout - indeterminate order processing outcome 

  # External system is unavailable

  Given an order in checkout
      And a shopper with a satisfactory risk profile
      And a valid form of payment
  When the shopper submits the order
  Then the shopper sees the advice that the system can't complete their order
      And the shopper sees the customer service contact information
      And the shopper's payment method is not charged

Option 2: Write separate features for the various elements of the process

I've done this when my foremost concern is testing at system or component boundaries, or when I'm interested in isolating the point of process failure when there is a problem. This approach also puts the focus on impediments to a valid request rather than on the overall integrated process. It does require many more features and scenarios, and it does require a shifting definition of what “externally observable behavior” means, but it remains human-readable and enables the features to be organized for use by different dev teams who might be collaborating on the overall solution. Testing with scenarios structured this way generally means inputs from systems outside the scope of the feature will have to be mocked, so it's no longer a true end-to-end acceptance test. But for dev teams who want to ensure that their applications still meet expectations of collaborating systems, this could be a useful approach that might complement contract tests or other assurance techniques.

Feature 1: Submit Order at Checkout

Scenario: System Accepts Order

  Given an order in checkout
      And the order has a valid shipping address
      And the order has a valid form of payment
  When the shopper submits the order
  Then the system accepts the order for processing
      And the system sends a request for payment authorization
      And the shopper sees an advice that their order is waiting for payment authorization

Scenario: System Can't Accept Order

  Given an order in checkout
      And the order has no delivery destination
      And the order has a valid form of payment
  When the shopper submits the order
  Then the system does not initiate order processing
      And the shopper sees and advice that they must provide shipping information

Feature 2: Authorize Payment

Scenario: Payment is Authorized

  Given a request for payment authorization
    And a valid and well-formed credit card number
    And a credit card expiration date in the future
    And the correct CVV code for the credit card
    And the correct postal code for the credit card account
  When the system submits the request for payment authorization
  Then the system receives an authorization code
    And the system advises the cart application that the payment has been authorized

Feature 3: Initiate Fulfillment

Scenario: Order Satisfies Fulfillment Conditions

  Given an order waiting for payment authorization
  When the cart receives a payment authorization advice
  Then the cart application validates the payment auhtorization code
      And the cart submits the order for fulfillment
      And the shopper sees an order confirmation advice
      And the system sends an order confirmation email

Conclusion

So there you have it – two ways to describe behavior that necessarily includes either intentional or possible pauses and timeouts that don't embed the pauses or timeouts inside the scenario. What do you think? I'm interested in learning from your comments!

Acknowledgements

I'm indebted to colleagues Jeff Siver, Nermin Dibek, Guillermo Diaz, Nicolas Perez, and Adrian Petras whose feedback and collaboration have meant so much.


This article was first posted to LinkedIn June 25, 2020.