Currently I'm creating some Cucumber features for a service. Let's say I have a service that is used for configuring Tesla cars:
public class TeslaCar {
Engine engine;
Color color;
// other things here...
}
where
public class Engine {
boolean isAllWheelDrive;
// for 60, 70, 90D, P100D
KilowattEnum kWh;
// other things here...
}
The simple create calls are easy to implement, I just use Given
combined with Add
to configure the resources then call the create.
So for CreateEngine
, I'd do:
Feature: CreateEngine
Scenario Outline: Create Engine
Given an engine was initialized
And engine has <all_wheel>
And kwh is <kwh>
When engine is created
Then engine creation succeeds
Examples:
| kwh | all_wheel |
| 60 | false |
| 60 | true |
| 70 | false |
And now I need to write an integration test for DriveCar
. I want to use Given
to ensure there is a new car that I can drive. I want to create a new car because I have no idea what the state of the past cars could be. If the battery level is at 10%, it won't be a good test. Then, since the integration test depends on the type of Tesla I have, I want to configure this in my feature file.
So it'd look like:
Feature: Drive Car
Scenario: Test drive Tesla
Given a car is initialized
And engine kwh is P90D
And engine is all wheel drive
And engine is created
# Need to call CreateEngine with above line, but is this clunky?
And car is created
# Need to call CreateCar above because Engine is a parameter to CreateCar
When car is driven
Then max speed is 120mph
This seems pretty reasonable at first, but is there a better way to do this? If more things needed to be configured for DriveCar
, then it would become unwieldy pretty fast.
One thing I thought of is to use @tags
. This would let me say, 'I need a 60kWh engine whenever I use @60kwh
'. But this doesn't extend well.
Don't configure the car and instead just use a default one.
Cucumber is designed for acceptance tests, tests which exercise the entire system (so they are also integration tests) as the user would and can be understood by stakeholders as well as by developers.
Your CreateEngine
scenario isn't for the entire system, but for a software component that only has meaning to developers, so I'd test it not with Cucumber but with a unit-testing framework.
Your "Drive Car" scenario, on the other hand, is an appropriate acceptance test. It has a lot of software detail, though. I'd write it something like this:
Feature: Drive Car
Scenario: Test drive Tesla
Given there is a car with an all-wheel-drive engine and P90D engine kwh
When the car is driven
Then the max speed is 120 mph
(I'm not sure that "P90D engine kwh" is correct grammar, so please correct as necessary.)
Important points:
I'm not sure whether you need more flexible car definition steps than I showed or not. I usually find that only a few simple steps are needed in most scenarios. Try to stay simple at first and build more complicated steps only if you need them.
Also, resist the urge to write Cucumber scenarios (or scenario outlines) for all combinations of data. Acceptance tests are slow and and take work to maintain, so you want to have as few as you can while still exposing all of the important requirements to stakeholders. When you start writing combinatorial Cucumber scenarios, think whether you can instead write one Cucumber scenario as an example and test all the combinations in unit tests.