How we can run more than one feature files and all feature files depending on the requirement using same runner class? - karate

I have 5 feature files I want to run some feature files depends on the requirement using one runner class only is it possible and if then how?

1) You can run required feature adding path to the feature in Karate Options:
#RunWith(Karate.class)
#KarateOptions(features = "classpath:animals/cats/required.feature")
public class CatsPostRunner {
}
2) You can run required feature or scenario adding a tag to the feature or scenario and in Karate Options:
#RunWith(Karate.class)
#KarateOptions(tags = "#someTag")
public class CatsPostRunner {
}
3) Also you can combine approach 1 and 2 :
#RunWith(Karate.class)
#KarateOptions(features = "classpath:animals/cats/required.feature", tags = "#someTag")
public class CatsPostRunner {
}
More info you find in Karate Options.

Related

Is there a way in karate to make use of TestExecutionListener from Junit5? [duplicate]

This question already has an answer here:
Karate summary reports not showing all tested features after upgrade to 1.0.0
(1 answer)
Closed 1 year ago.
I am trying to make use of https://junit.org/junit5/docs/current/user-guide/#launcher-api-listeners-custom, created my own Listener that implements TestExecutionListener:
public class JunitTestListener implements TestExecutionListener {
public static final Logger logger = LoggerFactory.getLogger(JunitTestListener.class);
/**
* Called when the execution of the {#link TestPlan} has finished,
* <em>after</em> all tests have been executed.
*
* #param testPlan describes the tree of tests that have been executed
*/
#Override
public void testPlanExecutionFinished(TestPlan testPlan) {
logger.info("Mutzu was here");
}
#Override
public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
logger.info("Mutzu was here");
}
}
I have create META-INF/services/org.junit.platform.launcher.TestExecutionListener and added there the custom listener class, however it is not called when running with Karate:
import com.intuit.karate.junit5.Karate;
class E2ETest {
// this will run all *.feature files that exist in sub-directories
// see https://github.com/intuit/karate#naming-conventions
#Karate.Test
Karate testAll() {
return Karate.run().relativeTo(getClass());
}
}
Any idea on how to make it work?
Thanks!
It seems that with this ExecutionHook I can have access to after/before step/scenario/feature however I cannot control the result of a scenario made up of other scenarios.
I can't possibly know in ExecutionHook what is a result of a "test", test in my acceptance meaning a scenario defined and composed with other scenarios. For example, if I have:
Background:
* def feature1 = read('classpath:create_schema.feature')
* def feature2 = read('classpath:create_dataset.feature')
* def feature3 = read('classpath:create_mergepolicy.feature')
Scenario: Some test
Given def schema = call feature1
And def schemaId = schema.schemaId
Given def datasetArg = { schemaId: '#(schemaId)' }
And def dataset = call feature2 datasetArg
And def datasetId = dataset.datasetId
Given def mergePolicyArg = { datasetId: '#(datasetId)' }
And def mergePolicy = call feature3 mergePolicyArg
And def mergePolicyId = mergePolicy.mergePolicyId
If there is a failure at some step, let's say call within feature1, then with ExecutionHook I get the failing event 2 times, one for scenario failing within feature1 and then another fail for Scenario: Some test, which is the test I run.
Any idea on how to have a single event triggered if some step fails in Scenario: Some test?
The Karate JUnit5 support is based on DynamicNode and is known to be not bound by the usual life-cycle. It is intended to make the developer experience better in IntelliJ and Eclipse, that's all.
Maybe you should be looking at the Karate ExecutionHook instead.

Creating common test data for multiple feature files

My requirement is as follows:
I have a couple of .feature files. I want to create test data that would be common to all of these feature files. Once the test data is created the scenarios will be run from the feature files.
I also want some info back after the test data is created. eg., ids of the data that i have created. So i can use this info to call the api's, add in payloads in my scenarios.
I think we could do this by:
1. Creating a junit java file. I define a static method with #BeforeClass in there and use Karate's runner() to run my create-test-data.feature file (I can use Karate to hit application api to create some data). I define a property in my java class of type Object and set it with the result of Runner.runFeature().
Then I create a separate feature file test-data-details.feature. I define my Java Interop code here. eg.,
def test_data =
"""
var JavaOutput = Java.type('com.mycompany.JavaFile');
var testData = JavaOutput.propertyName;
"""
Now that I have my test data object in my test-data-details.feature file. I call this .feature file (callonce) in the Background section of my feature files that have test scenarios in. So I can retries the test data details like id, name. etc that I can then use in the api request paths and payloads.
I am not sure if the above design is the correct way to go ahead. I tried but getting some issues in my Java file where getClass() below complains that it cannot be used in static method.
#RunWith(Karate.class)
public class AccountRunner {
public static Object job = null;
#BeforeClass
public static void create_job(){
Map<String, Object> result = Runner.runFeature(getClass(), "test-data.feature", null, true);
job = result.get("job");
}
}
Now all of the above can be totally wrong. Need help on how to tackle this scenario in Karate.
Thanks
From your question I understand you have a common test data feature file, which you want to run before all the test and hold that response in a variable that can be used in all of the test features.
You can also achieve this in karate-config.js using karate.callSingle()
In your karate-config.js
config["testdata"] = karate.callSingle("test-data.feature")
Your test-data.feature will be executed once before all the tests and store the response in testdata you can use this variable directly in your feature.
So i have implemented the following design:
I have created two methods one with BeforeClass and other with AfterClass annotation in my TestRunner.java file. In these methods I am able to call the specific data creation and clean-up feature files and pass args as Json object.
#RunWith(Karate.class)
#KarateOptions(tags = {"~#ignore"})
public class AccountRunner {
public static Map<String, Object> result = null;
#BeforeClass
public static void create_job() throws IOException, ParseException {
Class clazz = AccountRunner.class;
URL file_loc = clazz.getResource("create-test-data-1.json");
File file = new File(file_loc.getFile());
JSONParser parser = new JSONParser();
Object obj = parser.parse(new FileReader(file));
JSONObject jsonObject = (JSONObject) obj;
Map<String, Object> args = new HashMap();
args.put("payload", jsonObject);
result = Runner.runFeature(CommonFeatures.class, "create-data.feature", args, true);
}
#AfterClass
public static void delete_investigation() {
Map<String, Object> args = new HashMap();
args.put("payload", result);
Runner.runFeature(CommonFeatures.class, "delete-job.feature", args, true);
}
}
To run these tests via command line using "mvn test" command, i have done following changes in pom.xml.
`<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<includes>
<include>**/*Runner.java</include>
</includes>
</configuration>
</plugin>`
With this solution I able to run my tests in IDE by executing the runner directly or by command line. However, I have not found a way to run all of my tests by following the karate suggested approach where I have a *Test.java file at test suite level and I use default maven configuration with "mvn test". The features fails to run as the .feature file is called before the Runner file is executed which has method to create test data for tests.
Maybe someone can suggest what else, I could do to use Karate approach of running *Test.java file instead of each *Runner.java file.

Using Gatling for functional testing

I want to get into test automation, and I have already seen selenium that allows to do the functional test. I also saw gatling for performance testing and load/stress tests. I want to know if it is possible to do the functional tests with gatling?
This is an example for a functional spec from their documentation:
class GatlingFunSpecExample extends GatlingHttpFunSpec {
val baseURL = "http://example.com"
override def httpConf = super.httpConf.header("MyHeader", "MyValue")
spec {
http("Example index.html test")
.get("/index.html")
.check(pageHeader.exists)
}
}
object GatlingFunSpecExample {
def pageHeader = css("h1")
}
Link to the documentation:
https://gatling.io/docs/2.3/general/functional_specs/

How to run multiple feature files using the cucumber runner class?

Using the below line of code, all scenarios mentioned in login.feature can be executed.
#CucumberOptions(features= "src/main/resources/publish/login.feature", format = {"pretty"} )
If I have to execute multiple feature files, how do I define? Assuming if I define as below, features mentioned in publish folder would be executed.
#CucumberOptions(features= "src/main/resources/publish", format = {"pretty"} )
If I have to run multiple features and scenarios inside it, how do I define? Do i have to create multile cucumberRunner classes or i can define in one class file.
You can do it by defining tags value in cucumber option(considering that you have already grouped those scenarios in feature files)
Eg:
features="src/test/resources/FeatureFiles",tags="#feature1scenariogroup1,#feature2cenariogroup2"
Defining Tags Inside Feature File:
Feature: My Feature File
#smoke
Scenario: Login
Given I open "FireFox" browser
When I navigate to Sectionone "Home" page
And i do something
Then I Validate Something
#regression
Scenario: Compose Email
Given I open "FireFox" browser
When I Do An Action
#OnlyOneTime
Scenario:Send Email
....
Try this, the below code works for multiple feature files (tags attribute only works when you want to run particular scenario), I tried the below for multiple feature files, it worked:
#CucumberOptions(features = {"src\\test\\resources\\cucumberfeaturefolder\\cucumber1.feature",
"src\\test\\resources\\cucumberfeaturefolder\\cucumber2.feature"},
glue= "StepDef")
You can either use selective feature file or selective scenarios in the feature using tags. Please try with this solution.
Lets consider the you have n number of feature files and you need to run only selective feature from that. Then name each feature file with #tag name.
eg.: Under this folder, if you are having n number of features - "src/main/resources/publish"
1st Feature file name:
Login.feature
//Inside the file start with feature tag name
#Login
Feature: To Login to Email
//Then feature name followed with scenario tag name
#User
//Scenario1:
Scenario Outline: Navigate and logon to gmail application
Given User launches gmail application
When User updates emailID <emailID>
And User updates pwd <pwd>
Then User clicks on Login Button
Examples:
| emailID | pwd |
| a#gmail.com| 123 |
2nd Feature File name:
CreateEmail.feature
#Createmail
Feature: Create email
Scenario: Blah blah blah...
//Write all Given when And Then
3rd Feature File name:
SendEmail.feature
#Sendemail
Feature: Send email
Scenario: Blah blah blah...
//Write all Given when And Then
So From the above Test files. Lets consider you want to test 1st and 3rd feature alone, Then you can use code as below:
eg.: # This is to run specific feature files, which is 1 and 3. Likewise you can use the tags for scenario as well if you have n number scenario in same feature file.
#CucumberOptions(features= "src/main/resources/publish", tags="#Login, #Sendemail", format = {"pretty"} )
Modified my code like to run all enabled features, scenarios. features is the point to note here for the runner class to consider the features
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"classpath:features"},
plugin = {"html:target/site/cucumber-pretty","json:target/cucumber.json"},
tags = {"#currentTest"},
glue={"helpers","stepDefinitions"},
// dryRun = true,
monochrome = true
)
public class RunCukesTest{
}
You can simply write tags = {"#fileName1, #fileName2"}
We can add multiple files using #File1, #File2,..
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/java/Features"},
tags= {"#FirstTimeLaunch, #SignUpPage"},
glue= {"testCode"},
plugin = { "pretty", "html:target/htmlreports" }
)
Here all *.feature files inside your Features folder (Package) will be executed in the Alphabetic order of the file name, when you execute as a Junit test ( runner class )
Following code working for me:
(1) BeerCans.feature
Feature: Beer Cans
Scenario: Counting Beer Cans
Given I have <opening balance> beer cans
And I have drunk processed beer cans
When I go to my fridge
Then I should have <in stock> beer cans
(2) multiplication.feature
Feature: Multiplication
I multiply two numbers
Scenario: multiple a and b
Given I have variable a
And I have variable b
When I multiply a and b
Then I display the Result
(3) MyStepdefs class
package org.example.njain51.steps; /**
* #author : Nitin Jain
* #mailto : official.nitinjain#gmail.com
* #created : 5/22/2022, Sunday
**/
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
/**
What this program snippet doing?
**/
public class MyStepdefs {
#Given("I have <opening balance> beer cans")
public void iHaveOpeningBalanceBeerCans() {
System.out.println("I have Opening Balance");
}
#And("I have drunk processed beer cans")
public void iHaveDrunkProcessedBeerCans() {
}
#When("I go to my fridge")
public void iGoToMyFridge() {
System.out.println("I go to my Fridge");
}
#Then("I should have <in stock> beer cans")
public void iShouldHaveInStockBeetCans() {
System.out.println("I should have in stock beer cans");
}
}
(4) MultiplicationStepDef class
package org.example.njain51.steps; /**
* #author : Nitin Jain
* #mailto : official.nitinjain#gmail.com
* #created : 5/22/2022, Sunday
**/
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
/**
What this program snippet doing?
**/
public class MultiplicationStepDef {
#Given("I have variable a")
public void iHaveVariableA() {
System.out.println("I have variable a");
}
#And("I have variable b")
public void iHaveVariableB() {
System.out.println("I have variable b");
}
#When("I multiply a and b")
public void iMultiplyAAndB() {
System.out.println("I Multiply a and b");
}
#Then("I display the Result")
public void iDispayTheResult() {
System.out.println("I Display the result");
}
}
(5) RunCucumberTest Class for multiple feature implementation
package org.example.njain51;/**
* #author : Nitin Jain
* #mailto : official.nitinjain#gmail.com
* #created : 5/22/2022, Sunday
**/
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
#CucumberOptions(
features = {"src/test/resources/features/BeerCans.feature",
"src/test/resources/features/multiplication.feature"},
glue = {"org.example.njain51.steps"})
public class RunCucumberTest {
}
(6) Output when I run RunCucumberTest
C:\Users\offic\.jdks\corretto-1.8.0_292\bin\java.exe -ea -DnodeNamesHandler=org.jetbrains.plugins.cucumber.java.run.CucumberTestTreeNodeManager -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\lib\idea_rt.jar=49946:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\plugins\junit\lib\junit-rt.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\charsets.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\access-bridge-64.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\cldrdata.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\dnsns.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\jaccess.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\jfxrt.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\localedata.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\nashorn.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunec.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunjce_provider.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunmscapi.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\sunpkcs11.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\ext\zipfs.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jce.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jfr.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jfxswt.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\jsse.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\management-agent.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\resources.jar;C:\Users\offic\.jdks\corretto-1.8.0_292\jre\lib\rt.jar;D:\mylearning\SAMPLE_PROJECTS\Testing\cucumber-demo\target\test-classes;C:\Users\offic\.m2\repository\io\cucumber\cucumber-java\6.1.1\cucumber-java-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-core\6.1.1\cucumber-core-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-gherkin\6.1.1\cucumber-gherkin-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-gherkin-messages\6.1.1\cucumber-gherkin-messages-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\messages\12.1.1\messages-12.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\tag-expressions\3.0.0\tag-expressions-3.0.0.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-expressions\10.2.0\cucumber-expressions-10.2.0.jar;C:\Users\offic\.m2\repository\io\cucumber\datatable\3.3.1\datatable-3.3.1.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-plugin\6.1.1\cucumber-plugin-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\docstring\6.1.1\docstring-6.1.1.jar;C:\Users\offic\.m2\repository\io\cucumber\html-formatter\6.0.3\html-formatter-6.0.3.jar;C:\Users\offic\.m2\repository\org\apiguardian\apiguardian-api\1.1.0\apiguardian-api-1.1.0.jar;C:\Users\offic\.m2\repository\io\cucumber\cucumber-junit\6.1.1\cucumber-junit-6.1.1.jar;C:\Users\offic\.m2\repository\junit\junit\4.13\junit-4.13.jar;C:\Users\offic\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2021.1\plugins\cucumber-java\lib\cucumber-jvmFormatter.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 org.example.njain51.RunCucumberTest
I have Opening Balance
I go to my Fridge
I should have in stock beer cans
I have variable a
I have variable b
I Multiply a and b
I Display the result
Process finished with exit code 0

Geb page url method from ConfigSlurper

I am trying to store the urls I need in a config file that gets pulled using ConfigSlurper. I think this may not work but not sure. Thoughts?
You are probably looking for functionality provided by baseUrl configuration. When using to MyPage the url which is used by the browser is determined by combining basUrl configuration and the url property of your page class.
If you wanted a slightly cleaner method of doing this, you could implement a base page such as the one below - inner class for brevity and to avoid calling protected methods directly - (we have apps on 26 different subdomains!):
package page.admin
import geb.Configuration
import geb.Page
class AdminPage extends Page {
class WrappedConfig extends Configuration {
WrappedConfig(ConfigObject rawConfig) {
super(rawConfig)
}
String getAdminBaseUrl() {
return readValue('adminUrl', '<invalid-url>')
}
}
String getPageUrl() {
WrappedConfig config = new WrappedConfig(browser.config.rawConfig)
return config.adminBaseUrl + this.class.url
}
}
Your config might look something like this:
baseUrl = 'http://base-app.example.net'
adminUrl = 'http://admin-app.example.com'
This way, you can still use normal geb syntax:
given:
to PageWhichExtendsAdminPage, 'your-path', key1: 'value1
to generate the url http://admin-app.example.com/your-path/?key1=value1
I run geb on different locales so I encountered the same issue. I usually load the different urls out of a config file with locale.getCountry() as parameter for the environment.
In the running class I replace the baseUrl with the loaded entry with the ConfigSlurper. The advantage is that I can handle multiple locales and localhost environments. Testing locally vs testing the staging environment.
I have one main spock file containing the whole regression testing and a inheriting spock class for every country. The inheriting spock files doesn't contain much except the country/language encoding in the class name.
The config file:
environment{
CA{
url="ca.somewhere.com"
validZipCode=...
...
}
...
}
The main class:
class MainRegression extends GebReportingSpec{
#Shared Locale locale
def setupSpec(){
...
locale = ParameterReader.getLocale(this.class.name)
...
}
def "testing the website"(){
when: "entering the main url"
go URLService.getBaseUrl(locale)
...
}
The inheriting class:
#Stepwise
class CaEnRegressionSpec{} // Canada with english language
A good way to handle the at-verification with different languages / locales:
http://ldaley.com/post/1013531080/painless-page-identification-with-geb-grails