0

I am writing a feature which deals with adding multiple items to shopping cart like a typical e-commerce application.

It is something like this -

Scenario: Promotion is applied
    Given I select "Bacon" worth "$1"
    Given I select "Lettuce" worth "$2"
    Given I select "Diet Coke" worth "$5"
    Given I select "Bread" worth "$2"
    Then  "$0.5" promotion should be applied for "Bacon"
    Then  "$0.0" promotion should be applied for "Lettuce"
    Then  "$0.5" promotion should be applied for "Diet Coke"
    Then  "$1.0" promotion should be applied for "Bread"
    Then  total paid should be "$8"

Needless to say, the stepdefs.js look something like this:

Given(/^I select "([^"]*)" worth "([^"]*)"$/, function (item, price) {
 //addToCart
});

etc.

There is another scenario which is similar and adds clothes instead of food items.

If I am using Scenario outline and Examples it turns to this:

Scenario Outline: Promotion is applied
    Given I select "<item>" worth "<price>"
    Given I select "<item>" worth "<price>"
    Given I select "<item>" worth "<price>"
    Given I select "<item>" worth "<price>"
    Then  "<discount>" promotion should be applied for "<item>
    Then  "<discount>" promotion should be applied for "<item>
    Then  "<discount>" promotion should be applied for "<item>
    Then  "<discount>" promotion should be applied for "<item>
    Then  total paid should be "$8"

Examples:

 | item | price | discount | 
 | "Bacon" | "$1" | 0.5
 | "Lettuce" | "$2" | 0.0
 | "Diet  Coke" | "$5" | 1.0
 | "Bread" | "$2" | 0.5

But it runs the test once per row (so four tests are run), what I essentially want is running all of them for one test.

In fact I want to run them as 4 items added for food vs 2 items added for clothes. So,

Scenario Outline: Promotion is applied <type>
    Given I select "<item>" worth "<price>"
    Then  "<discount>" promotion should be applied for "<item>"
    Then  total paid should be "<total>"

Examples:

type | items & prices & promotion (may be some object like that?) | total
food | [ {"Bacon - $1 - 0.5"}, {"Lettuce - $2 - 0.0"}, {"Diet  Coke - $5 - 1.0"}, {"Bread - $2 - 0.5"} ] /*takes an array*/ | $8
clothes | [{"pant - $50 - 10"}, {"shirt - $25 - 5"}] | $60

Is it even possible? How do one achieve that?

Thanks

[EDIT]: This is just an example question, I've removed all complications and this is just a nailed down version. My idea is to get a way to use array of objects in scenarios. Please do not go by the name and numbers mentioned in the question.

0

2 Answers 2

1

Putting figures in scenarios is a really good way to dramatically increase the cost of change, whilst at the same time creating fragile tests with high maintenance costs. So don't do it.

In addition you are not clearly stating what you are testing and you are repeating yourself.

From what you have written I can see lots of different behaviour you might be specifying here.

You should write separate scenarios for these things. So you could have scenarios like

Scenario: Promotion affects all products in the basket
  Given a have a basket with several products
  And I have applied a promotion
  When I go to the checkout
  Then I should see a discount applied to each product

Scenario: Some products are not discountable

to deal with the actual value of the discount

Scenario: Correct discount rate is applied for a promotion
  Given a promotion with a 20% discount
  And a basket of products
  When I go to the checkout
  Then I should see a 20% discount

etc. etc.

Note: Doing calculations like in your examples is a particularly effective way of making your scenarios expensive to maintain, and to increase the cost of change of your application.

Consider your example. It has several business rules hidden in the figures. Some of these probably are:

  • lettuce is not discounted by promotions
  • bacon is half price (or is that any quantity of bacon gets 50c off?) ...

Note how none of these rules a clearly specified in you example scenarios, you have to infer (guess) the rule from the example.

Now all of these are rules that must somehow be encoded in your application (hopefully in the promotion and products). What happens when

  • lettuce becomes discountable
  • bacon supplies are tight so you can't discount it any more

With your current approach what happens is that you tests fail and you have to re-write the scenarios to reflect your new business conditions - so you have dramatically increased the cost of change.

The simple rule for this stuff is don't put calculated numbers in scenarios. The fuller more complex rule is that all examples in scenarios should mature into concise verbal expressions of business rules. They should capture the WHAT i.e. that some products can have a percentage discount, rather than HOW i.e. bacon is currently 50c per pound cheaper. Then if someone makes the simple config change that bacon is no longer discountable you don't have your tests breaking because of this.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi, thanks for responding. I understand what you are saying. This was just an example that I put up here. 0.0 for lettuce doesn't mean it is non-discountable. Nor does 0.5 mean percent or cent. These were just some random numbers I put up here. My question essentially was, it there a way we can provide custom objects (array of custom objects) in the data tables. So, if you look at the last Examples section in my question, is it possible to do that?
The answer still stands. Examples and data tables don't belong in mature scenarios for the reasons stated. A better approach is for each example set examine what business rules the examples represent and write scenarios for each of those business rules
1

A second answer is that

Cucumber is not a testing tool, if you want to write data driven tests use a testing tool like a unit test tool.

1 Comment

Again, this was just an example question. I agree unit test is more efficient, but in our case we can't use unit test for some reason. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.