Cucumber - gherkin : Scenario outliner : scenario.log for each outliner iteration - cucumber

I would like to log on to the cucumber report ids generate on the cucumber steps.
to do this I have saved the scenario on the Hook files
public void beforeUITest(Scenario scenario) {
test.scenario = scenario;
and later in the code, I use the code to log the ids that I need :
test.scenario.log(ids);
this work perfectly if we are using simple scenario.
But when Scenario outliner is used all the ids is logged under the same example and not splitted on different execution
Scenario Outline AAAA <testDetails>
Hooks
Steps
When a new file FileName
Output 1
E2EDHZBPBWW
E2EGQZ2UHJA
E2E5FFFHMLG
E2ECIKJXRHX
E2ETR6BAXOV
Then a dddd
the above ids must be once for each example

Related

Associate existing shared steps with a test case programmatically

I am trying to add a shared step to a test case that is being created using
CreateWorkItemAsync()
It is no problem to create test steps and add them to the test case
ITestStep testStep1 = testBase.CreateTestStep();
but I am trying to add an existing shared step to the test case. I cannot find a way in the Azure Devops SDK to do so.
There is a ISharedStepReference Interface which used to call a shared step set from a test case.
You should be able to add a shared step into a specific test case. A code snippet for your reference:
ITestManagementService testService = tfsCollection.GetService<ITestManagementService>();
ITestManagementTeamProject teamProject = testService.GetTeamProject(teamProjectName);
//find test case by testcase id
ITestCase testcase1 = teamProject.TestCases.Find(192); //192 is the testcase id
//find share steps by sharedstep id
ISharedStep sharedStep1 = teamProject.SharedSteps.Find(140); //140 is the shared step id
//Add shareSteps to the specific test case
ISharedStepReference sharedStepReference = testcase1.CreateSharedStepReference();
sharedStepReference.SharedStepId = sharedStep1.Id;
testcase1.Actions.Add(sharedStepReference);
testcase1.Save();
What I ended up doing is creating the test case using
CreateWorkItemAsync()
and then getting that work item using
GetWorkItemAsync()
and then editing the field
Microsoft.VSTS.TCM.Steps
as xml and inserting my own nodes into the proper places to add shared steps to the test case. You can see the format of the shared steps by getting a test case with an API GET request and looking at the format of Microsoft.VSTS.TCM.Steps.

How to implement multithreading in groovy?

I want to create 10 million customers for performance testing. I am running a basic groovy script for creating a customer with only mandatory attributes. Then I am running the script inside a loop.
How can I improve the performance of this groovy script?
I can't find the corresponding multi-threading options that are available in impex import.
Is there a better way of creating 10 million customers in Hybris?
Edit 1:
Sample groovy script for generating customers with different id's.
import com.google.common.collect.ImmutableSet
import de.hybris.platform.core.model.user.AddressModel
import de.hybris.platform.core.model.user.CustomerModel
//Setting only mandatory attributes
for(int i=0; i<100000; i++) {
customerModel = new CustomerModel()
id = new Random().nextInt(100000000)
uid = 'TestCustomer_'+id
customerModel.setUid(uid)
name = 'Test Customer Name_'+id
customerModel.setName(name)
addressModel = new AddressModel()
addressModel.setOwner(customerModel)
customerModel.setDefaultPaymentAddress(addressModel)
customerModel.setDefaultShipmentAddress(addressModel)
try{
modelService.save(customerModel)
}catch(Exception e){
println('Creation of customer with id = '+uid+' and amway account = '+code+' failed with error : '+e.getMessage())
}
}
I would say the logical answer is to use Impex files. This allows creation bulk and has support for multithreading: https://help.hybris.com/1811/hcd/44f79c4e604a4bff8456a852e617d261.html
basically you can configure the number of workers or threads:
impex.import.workers=4
You would be responsible for converting your input format to either *.csv or *.impex
addition:
Regarding the Groovy script, you can set the uid and name with impex, only you would have to provide the random numbers in advance. You could do this in Excel or in some scripting language.
You could even do it in the impex itself with code execution.
But if you just want a lot of random customers: you could also just spin up 10 browser windows with /hac and run the script ten times.
I created multiple ScriptingJob with the above groovy script and attached them to 30 different Cronjobs. Executing all of them in parallel achieved the same result.

Passing input from Excel to test class

I have a multiple test cases in single class. Test Excel has three different worksheets/tabs 1, 2 and 3. There are three test cases in my test class.
I looked into data provider annotation; what I understood is it will execute same test case for whole object passed. In my case it will test test case 1 first for all rows from tab 1, test case 2 for all rows from tab 2 and so on.
What I am looking for is as below:
for i number of rows in excel
Execute test 1 with row i from tab 1
Execute test 2 with row i from tab 2
Execute test 3 with row i from tab 3
(Form i complete, proceed to second form data)
What I could do is read the whole Excel put it in object[][]. Create data providers for each test case and let them run in for loop. For example:
CLASS
{
for loop
{
data provider 1, 2, 3;
#Test
function testcase1()
#Test
function testcase2()
#Test
function testcase3()
}
}
Is it valid approach or does it defeat the purpose of TestNG?
This approach is called Data-driven testing. Your particular case is a type of the DB part
Data pools
ODBC sources
CSV files
Excel files
DAO objects
ADO objects
IMHO the TestNG feature - parametric testing, is using the same approach. It allow you to run the same test over and over again using different values.
I'm not a big fan of the static test data (see Pesticide paradox), my advice is you either generate your Excel files per run (as a Fresh Fixture) or you pass a dynamically generated test data to your tests.
DataProvider takes Method as argument as well.
You can return objects based on the testmethod call.
i.e. if testmethod.name = testcase1 - read tab 1 - create object and return
...and so on

Passing list of values to Cucumber scenario outline

I have a scenario to validate 100 employee names, The QueryString will return them in xml format.All I want to do is to validate all the employee names in an Assertion statement like given below. Instead of adding each name in the Scenario Outline Example, Is it possible to send a list of 100 employee names as input so that I can Iterate through them in java and could easily validate in Assertion condition. Please advice.
Scenario Outline: When the User queries for employee information, the correct records are returned
Given the webservice is running
When the User queries for employee information "<QueryString>"
Then the User receives correct data "<Name>"
Examples:
|QueryString|Name|
|Some localhost url|Peter|
|Some localhost url|Sam|
.
.
#Then("^the User receives correct data\"([^\"]*)\"$")
public void the_user_receives_correct_data(String arg1) throws Throwable {
queryResultPage = selenium.getPageSource();
assertTrue(queryResultPage.contains(arg1));
}
so i will answere here to LINGS comment
What you can do, is use these filenames in your step definition to load the files in your code. Cucumber doesnt support direct file loading as far as i know.
i use something like this to locate full ressource pathes for my relative path file names:
public static String getAbsoluteResourcePath(String resourcePath) {
if (SystemUtils.IS_OS_WINDOWS) {
return Utils.class.getResource(resourcePath).getPath().substring(1).replace("/", File.separator);
} else {
return Utils.class.getResource(resourcePath).getPath().replace("/", File.separator);
}
}
The resourcePath should then be your relative file path
What you are looking for is external test data support, which is supported with QAF. You can use any inbuilt data provider with interceptor to modify data set or custom data provider.
If you are using cucumber version 5+ you can use qaf-cucumber that will give you all qaf features with cucumber. For lower version you can run your existing feature files with QAF runner.

How to use common/shared "blocks" between cucumber features?

I'm new to cucumber, but enjoying it.
I'm currently writing some Frank tests, and would like to reuse blocks of cucumber script across multiple features - I'd like to do this a the cucumber level if possible (not inside the ruby).
For example, I might have 4 scripts that all start by doing the same login steps:
given my app has started
then enter "guest" in "user-field"
and enter "1234" in "password-field"
and press "login"
then I will see "welcome"
then *** here's the work specific to each script ***
Is there any way to share these first 5 lines across multiple scripts? Some kind of "include" syntax?
Generally there are 2 approaches:
Backgrounds
If you want a set of steps to run before each of the scenarios in a feature file:
Background:
given my app has started
then enter "guest" in "user-field"
and enter "1234" in "password-field"
and press "login"
then I will see "welcome"
Scenario: Some scenario
then *** here's the work specific to this scenario ***
Scenario: Some other scenario
then *** here's the work specific to this scenario ***
Calling steps from step definitions
If you need the 'block' of steps to be used in different feature files, or a Background section is not suitable because some scenarios don't need it, then create a high-level step definition which calls the other ones:
Given /^I have logged in$/ do
steps %Q {
given my app has started
then enter "guest" in "user-field"
and enter "1234" in "password-field"
and press "login"
then I will see "welcome"
}
end
Also, in this case I'd be tempted not to implement your common steps as separate steps at all, but to create a single step definition: (assuming Capybara)
Given /^I have logged in$/ do
fill_in 'user-field', :with => 'guest'
fill_in 'password-field', :with => '1234'
click_button 'login'
end
This lends a little bit more meaning to your step definitions, rather than creating a sequence of page interactions which need to be mentally parsed before you realise 'oh, this section is logging me in'.
A better approach is suggested to use ruby level "methods" to code reuse instead of nested steps from code maintenance and debugging perspective.
Here is the link to more detail:
Reuse Cucumber steps
Description
The following method proposes an alternative approach to one of the solutions described in Jon M's answer.
Namely, instead of calling nested steps inside step definitions, such common blocks of steps can be extracted into external .feature files which can be included into your feature file (in a manner of speaking).
How-to
1. Expose utility / helper methods to be able to run steps parsed from a .feature file
# features/support/env.rb
# expose Cucumber runtime
InstallPlugin do |_, registry|
runtime = registry.instance_variable_get('#registry').instance_variable_get('#runtime')
Cucumber.define_singleton_method(:runtime) { runtime }
end
# extend current World with methods to run dynamic (already parsed) steps
Before do
step_invoker = Cucumber::Runtime::SupportCode::StepInvoker.new(Cucumber.runtime.support_code)
define_singleton_method(:dynamic_steps) do |steps|
steps.each do |step|
dynamic_step(step)
end
end
define_singleton_method(:dynamic_step) do |step|
LOGGER.info("Running template step: #{step[:text]}")
step_invoker.step(step)
end
end
2. Create a template file which will contain the steps to be shared
# features/templates/my_profile.template.feature
#template
Feature: Steps to navigate to my_profile_page
Scenario: login_page
Given my app has started on "login_page"
And I enter "guest" in "user-field" on "login_page"
And I enter "1234" in "password-field" on "login_page"
And I press "login" on "login_page" and go to "welcome_page"
Scenario: welcome_page
Given that I am on "welcome_page"
And I click "my_profile_button" on "welcome_page" and go to "my_profile_page"
Scenario: my_profile_page
...
3. Create an utility module which will parse steps from a .feature file
# features/support/template_parser.rb
require 'gherkin/parser'
require 'gherkin/pickles/compiler'
module TemplateParser
class << self
def read_from_template(template_path, from: nil, till: nil)
pickles = load_template(template_path)
flow = construct_flow(pickles)
slice_flow(flow, from, till)
end
private
def load_template(template_path)
source = {
uri: template_path,
data: File.read(template_path),
mediaType: 'text/x.cucumber.gherkin+plain'
}
def source.uri
self[:uri]
end
gherkin_document = Gherkin::Parser.new.parse(source[:data])
id_generator = Cucumber::Messages::IdGenerator::UUID.new
Gherkin::Pickles::Compiler.new(id_generator).compile(gherkin_document, source)
end
def construct_flow(pickles)
pickles.to_h do |pickle|
[
pickle.name,
pickle.steps.map(&:to_h).map { |step| step[:argument] ? step.merge(step[:argument]) : step }
]
end
end
def slice_flow(flow, from, till)
raise NameError, "From step '#{from}' does not exist!" unless from.nil? || flow.keys.include?(from)
raise NameError, "Till step '#{till}' does not exist!" unless till.nil? || flow.keys.include?(till)
from_idx = from.nil? ? 0 : flow.keys.index(from)
till_idx = till.nil? ? -1 : flow.keys.index(till)
flow.slice(*flow.keys[from_idx...till_idx])
end
end
end
4. Create a step definition that will load this template and inject the specified steps dynamically at runtime
And('I complete the {string} template from the {string} until the {string}') do |template, from, till|
template_path = "features/templates/#{template}.template.feature"
flow = TemplateParser.read_from_template(
template_path,
from: from.empty? ? nil : from,
till: till.empty? ? nil : till
)
flow.each_value { |steps| dynamic_steps(steps) }
end
5. Use this step inside your main feature file, by declaring which blocks of steps to use
# features/tests/welcome.feature
Feature: User is welcomed
Scenario: Verify that user sees welcome text
Given I complete the 'my_profile' template from the 'login_page' until the 'my_profile_page'
Then I see 'welcome' on 'welcome_page'
6. Make sure you omit the #template .feature files from being run in your tests
$ bundle exec cucumber --tags ~#template
Limitations
Con:
This method exposes some internals of the private API of cucumber-ruby, which may change in future.
Con:
This is a non-standard way of sharing steps between feature files.
Helper methods are the preferred way to achieve this, as per FAQ.
Pro:
The common blocks of steps are syntax-highlighted, and have proper IntelliSense support in your editor of choice.
Pro:
You can encode entire "workflows" easily this way, allowing you to encode your workflow expectations in a DRY way.
Namely, you can reuse those workflow steps by completing the first part of a workflow, change a few things on a single page as per your test requirements, resume those workflow steps from the follow-up page, and add an appropriate verification at the end of the workflow that covers those test requirements.

Resources