I'm trying to write a cucumber test for part of our application (I'm completely new to cucumber, and writing acceptance tests really), and I have a step in the test, which I want to do one of 2 different things. I want it to either check for a specific value, or check for a system default value.
This is what I came up with
Scenario Outline: English News
Given with the locale is set to '<language>'
When a user views the page
Then they see the <image> image
Examples:
| language | image |
| en-gb | default |
| fr | "french.png" |
This then hits one of 2 different step definitions,
#And("^they see the default image$")
public void defaultImage() throws Throwable {
// check for system default
}
#And("^they see the \"(.*)\" image$")
public void customImage(String image) throws Throwable {
// check for specific value from the input
}
Is this the correct way to do this? My TL has suggested that I should actually only have the one step def, and pass "default" as the input, and then do a conditional check inside the step def, like this:
#And("^they see the \"(.*)\" image$")
public void checkImage(String image) throws Throwable {
if ("default".equals(image)){
// check for system default
} else {
// check for specific value from the input
}
}
Which is the correct way to do this? Any help is greatly appreciated.
your default image must have a real name, right ? so why not validating its real name ? because "default" could be anything so not everyone may understand the same thing.
If you do this, indeed you need only one step def. I wouldn't put an if check, I would assert the real name. You can maybe add a comment in your example table saying that the first value is the default, so that it's clear for everyone in your team.
Related
How can I fetch a list of all the scenarios that have a particular tag. For example
get all scenarios that have #checkout tag.
Lets assume you have 15-20 Scenarios/Scenarios Outline tagged with #checkout.
#checkout
Scenario Outline: Validation of UseCase Guest User Order Placement flow from Search
Given User is on Brand Home Page <Site>
And User searches for a styleId and makes product selection on the basis of given color and size
| Style_ID | Product_Size | Product_Color |
| TestData1 | TestData1 | TestData1 |
| TestData2 | TestData2 | TestData2 |
Then Clicking on Cart icon shall take user to Shopping Bag
Please follow this way to fetch name of scenarios.
File name Hook.java
#Before
public void setUpScenario(Scenario scenario){
String scenarioName = scenario.getName();
//Either you can write down name of the scenario under a file system like excel or implement in the way you want
}
Please lets know if you find it meaningful and it solved your problem.
Dry run to the rescue.
Dry run gives you a way to quickly scan your features without actually running them.
Try the following CucumberOptions annotations (this is Java/Junit version, but the idea applies everywhere)
#RunWith(Cucumber.class)
#CucumberOptions(plugin = { "pretty", "html:target/cucumber-html-report", "json:target/cucumber.json" }, glue = {
"some.stepdef" }, features = { "src/cucumberTest/featureFiles" }, tags = { "#now" }
,dryRun = true, strict=true)
public class CucumberNowTestDryRunner {
}
The cucumber report will look like this
I had feature declaration like this:
Feature: find taxi and minicabs information
in order to get taxi and minicabs contact at given location
as application developer
I want to find tax and minicabs contact information at given location or query options
Scenario Outline: find taxi and minicabs contact information
Given Joe at location with <lat> and <lon>
When get all taxi and minicabs contacts information
Then should see list of taxi and minicabs
And all of them are at location with <lat> and <lon>
Examples:
| lat | lon |
| 51.490075 | -0.133226 |
And I had step definition like this:
#Given("^Joe at location with ([+-]?([0-9]+[.])?[0-9]+) and ([+-]?([0-9]+[.])?[0-9]+)$")
public void joeAtLocationWithLatAndLon(Number lat, Number lon) throws Throwable {
....
}
I expected I can received 2 parameters but Cucumber passed to me 4 parameters.
Error message as below:
with pattern [^Joe at location with ([+-]?([0-9]+[.])?[0-9]+) and ([+-]?([0-9]+[.])?[0-9]+)$] is declared with 2 parameters. However, the gherkin step has 4 arguments [51.490075, 51., -0.133226, 0.].
Do you have any idea about this? btw, I very appreciate if you can explain the way cucumber identify the number of parameters or share me any document about that.
The issue is the two inside brackets inside the regular expression. Using the current regex you will get 2 groups - one the whole "51.490075" and second "51." which matches the exp in the ([0-9]+[.]) part. Thus 4 arguments are created.
Remove the inside brackets and you will get just one argument for each, so two in total.
The next problem you are going to have is cucumber does not know how to transform String to Number class unless you tell it. For this you need to make use of the Transform annotation and create a specific class for this.
import cucumber.api.Transformer;
public class NumberTransformer extends Transformer<Number>{
#Override
public Number transform(String value) {
return Double.parseDouble(value);
}
}
#Given("^Joe at location with ([+-]?[0-9]+[.]?[0-9]+) and ([+-]?[0-9]+[.]?[0-9]+)$")
public void joeAtLocationWithAnd(#Transform(NumberTransformer.class)Number arg1, #Transform(NumberTransformer.class)Number arg2) throws Exception {
System.out.println(arg1);
System.out.println(arg2);
}
For the transforming issue you can also look up xstreams. If you are using cucumber 2, these kind of transformation is easier by using Xstreamconvertor annotation - https://github.com/cucumber/cucumber-jvm/pull/1010
I have a simple piece of code where I want to run a first run operation in the beginning and let the default dialog handle everything else. In the code below.
bot.dialog('/firstRun', [firstRun1])
function firstRun1(session) {
session.replaceDialog('/')
}
bot.dialog('/', new builder.IntentDialog()
.matches(/wishlist/, '/wishlist')
.matches(/exclusive/, '/exclusive')
.onDefault('/runCampaign')
)
bot.dialog('/wishlist', (session, args) => {
session.endDialog('Add to wishlist')
})
bot.dialog('/exclusive', (session, args) => {
session.endDialog('Exclusive')
})
bot.dialog('/runCampaign', [runCampaign1])
function runCampaign1(session) {
session.send('default')
}
My problem is right here. When the person types exclusive I believe the default dialog will run its matches and should ideally trigger exclusive no matter how many times but for some reason its not happening that way as per the screenshot below. Once a person types exclusive or wishlist at the start it always runs the default at the bottom, how can I fix this. Also how to share data commonly between the different match clauses in the IntentDialog, lets say I want to have some variable session.dialogData.name across the matches and the default
UPDATE 1
Instead of saying session.endDialog inside the 2 areas in my code above, I simply wrote session.send() without ending any dialogs and now nothing happens when i type exclusive or wishlist. Am I missing something?
You should always call session.endDialog if you want to return to the calling(previous) dialog.
In your first example:
|current dialog|user input|next dialog|
|first run |go | / |
| / |whishlist | / |
| / |freak |runCampaign|
|runCampaign |<any> |runCampaign|
as you didn't call session.endDialog in the runCampaign dialog, you will always be in it and on any user input the 'default' will be printed.
In you second example, you missed to type "whishlist", so you immediately got into the runCampaign dialog. So, you changes to send there not called. But if you were typed 'whislist' as in the first example before "freak", you would have gotten into wishlist and you would always have printed "Added to wishlist" on any input.
In AfterScenario method, I want to get the rows from table "Examples" in Scenario Outline, to get the values in it, and search that specific values in the database
I know that this can be achieved by using Context.Scenario.Current...
Context.Scenario.Current[key]=value;
...but for some reason I'd like to be able to get it in a simpler way
like this:
ScenarioContext.Current.Examples();
----------- SCENARIO --------------------------------
Scenario Outline: Create a Matter
Given I create matter "< matterName >"
Examples:
| matterName |
| TAXABLE |
----------AFTER SCENARIO -----------------------------------
[AfterScenario()]
public void After()
{
string table = ScenarioContext.Current.Examples();
}
So if you look at the code for ScenarioContext you can see it inherits from SpecflowContext which is itself a Dictionary<string, object>. This means that you can simply use Values to get the collection of values, but I have no idea if they are Examples or not.
The best solution I came up with was to infer the examples by keeping my own static singleton object, then counting how many times the same scenario ran.
MyContext.Current.Counts[ScenarioContext.Current.ScenarioInfo.Title]++;
Of course, this doesn't work very well if you don't run all the tests at the same time or run them in random order. Having a table with the examples themselves would be more ideal, but if you combine my technique along with using ScenarioStepContext you could extract the parameters of the Examples table out of the rendered step definition text itself.
Feature
Scenario Outline: The system shall do something!
Given some input <input>
When something happens
Then something should have happened
Examples:
| input |
| 1 |
| 2 |
| 3 |
SpecFlow Hook
[BeforeStep]
public void BeforeStep()
{
var text = ScenarioStepContext.Current.StepInfo.Text;
var stepType = ScenarioStepContext.Current.StepInfo.StepDefinitionType;
if (text.StartsWith("some input ") && stepType == StepDefinitionType.Given)
{
var input = text.Split(' ').Last();
}
}
The business scenario I'm trying to test with cucumber/gherkin (specflow, actually) is that given a set of inputs on a web form, I make a request, and need to ensure that (under certain conditions), when the result is returned, a particular field hasn't changed (under other condition, it does). E.g.
Given I am on the data entry screen
When I select "do not update frobnicator"
And I submit the form
And the result is displayed
Then the frobnicator is not updated
How would I write the step "the frobnicator is not updated"?
One option is to have a step that runs before "I submit the form" that reads something like "I remember the value of the frobnicator", but that's a bit rubbish - it's a horrible leak of an implementation detail. It distracts from the test, and is not how the business would describe this. In fact, I have to explain such a line any time anyone sees it.
Does anyone have any ideas on how this could be implemented a bit nicer, ideally as written?
I disagree with the previous answer.
The gherkin text you felt like you wanted to write is probably right.
I'm going to modify it just a little to make it so that the When step is the specific action that is being tested.
Given I am on the data entry screen
And I have selected "do not update frobnicator"
When I submit the form
Then the frobnicator is not updated
How exactly you Assert the result will depend on how your program updates the frobnicator, and what options that gives you.. but to show it is possible, I'll assume you have decoupled your data access layer from your UI and are able to mock it - and therefore monitor updates.
The mock syntax I am using is from Moq.
...
private DataEntryScreen _testee;
[Given(#"I am on the data entry screen")]
public void SetUpDataEntryScreen()
{
var dataService = new Mock<IDataAccessLayer>();
var frobby = new Mock<IFrobnicator>();
dataService.Setup(x => x.SaveRecord(It.IsAny<IFrobnicator>())).Verifiable();
ScenarioContext.Current.Set(dataService, "mockDataService");
_testee = new DataEntryScreen(dataService.Object, frobby.Object);
}
The important thing to note here, is that the given step sets up the object we are testing with ALL the things it needs... We didn't need a separate clunky step to say "and i have a frobnicator that i'm going to memorise" - that would be bad for the stakeholders and bad for your code flexibility.
[Given(#"I have selected ""do not update frobnicator""")]
public void FrobnicatorUpdateIsSwitchedOff()
{
_testee.Settings.FrobnicatorUpdate = false;
}
[When(#"I submit the form")]
public void Submit()
{
_testee.Submit();
}
[Then(#"the frobnicator is not updated")]
public void CheckFrobnicatorUpdates()
{
var dataService = ScenarioContext.Current.Get<Mock<IDataAccessLayer>>("mockDataService");
dataService.Verify(x => x.SaveRecord(It.IsAny<IFrobnicator>()), Times.Never);
}
Adapt the principle of Arrange, Act, Assert depending on your circumstances.
Think about how you would test it manually:
Given I am on the data entry screen
And the blah is set to "foo"
When I set the blah to "bar"
And I select "do not update frobnicator"
And I submit the form
Then the blah should be "foo"