Run each cucumber test independently - java

I'm using cucumber and maven on eclipse and what I'm trying to do is run each test independently. For example I have a library system software that basically allows users to borrow books and do other stuff.
One of the conditions is that users can only borrow a max of two books so I wrote to make sure that the functionality works. This is my feature file:
Scenario: Borrow over max limit
Given "jim#help.ca" logs in to the library system
When "jim#help.ca" order his first book with ISBN "9781611687910"
And "jim#help.ca" orders another book with ISBN "9781442667181"
And "jim#help.ca" tries to order another book with ISBN "1234567890123"
Then jim will get the message that says "The User has reached his/her max number of books"
I wrote a corresponding step definition file and every worked out great. However, in the future I want to use the same username ("jim#help.ca") for borrowing books as though jim#help.ca has not yet borrowed any books. I want each test to be independent of each other.
Is there any way of doing this...maybe there's something I can put into my step definition classes such as a teardown method. I've looked into it but I couldn't fine any solid information about it. If there's a way please help me. Any help is greatly appreciated and I thank you in advance!

Yes, you can do setups and teardowns before and after each scenario, but it's not in the step definition file. What you want to use are hooks.
Hooks run before or after a scenario and can run before/after every scenario or just the ones you and #tag to, for example:
#remove_borrowed_books
Scenario: Borrow over max limit
Unfortunately I have only used cucumber with ruby not java so I can't give you step-by-step instructions, but this should tell you what you need to know https://zsoltfabok.com/blog/2012/09/cucumber-jvm-hooks/

You can use the "#After" hook to achieve this as #Derek has mentioned using for example a Map of books borrowed per username:
private final Map<String, Integer> booksBorrowed = new HashMap<>();
#After
public void tearDown() {
booksBorrowed.clear();
}
#Given("...")
public void givenUserBorrowsBook(String username) {
booksBorrowed.put(username, booksBorrowed.containsKey(username) ? booksBorrowed.get(username) + 1 : 1);
....
}
Or the "#Before" hook to perform the cleanup before each scenario is executed, which is the option I would recommend:
private Map<String, Integer> booksBorrowed;
#Before
public void setUp() {
booksBorrowed = new HashMap<>();
}
If you are planning to run scenarios in parallel then the logic will be more complex as you will need to maintain the relationship between the thread executing a particular scenario and the usernames used on that thread.

Related

Cucumber Scenarios to be run in Sequential Order

I have few concerns regarding cucumber framework:-
1. I have single Feature file(steps are dependent on each other)and i want to run all the scenarios in order, by default they are running in random order.
2. How to run a single feature file multiple times?
I put some tags and tried to run but no luck.
#Given("Get abc Token")
public void get_abc_Token(io.cucumber.datatable.DataTable dataTable) throws URISyntaxException {
DataTable data=dataTable.transpose();
String tkn= given()
.formParam("parm1",data.column(0).get(1))
.formParam("parm2", data.column(1).get(1))
.formParam("parm3", data.column(2).get(1))
.when()
.post(new URI(testurl)+"/abcapi")
.asString();
jp=new JsonPath(tkn);
Token=jp.getString("access_token");
if (Token==null) {
Assert.assertTrue(false,"Token is NULL");
}else {
}
}
#Given("Get above token")
public void get_abovetoken(io.cucumber.datatable.DataTable dataTable) throws URISyntaxException {
System.out.println("Token is " +Token);
}
}
So in the above steps i am getting token from one step and trying to print token in other step but i got null and not the actual value, because my steps are nunning randommmally
Please note i am running TestRunner via testng.xml file.
Cucumber and testing tools in general are designed to run each test/scenario as a completely independent thing. Linking scenarios together is a terrible anti-pattern don't do it.
Instead learn to write scenarios properly. Scenarios and feature files should have no programming in them at all. Programming needs to be pushed down into the step definitions.
Any scenario, no matter how complicated can be written in 3 steps if you really want to. Your Given can set up any amount of state. Your When deals with what you are doing, and your Then can check up any number of conditions.
You do this by pushing all the detail down out of the scenario and into the step definitions. You improve this further by having the step definitions call helper methods that do all the work.

CommandExecuteIn Background throws a "Not an (encodable) value" error

I am currently trying to implement file exports in background so that the user can do some actions while the file is downloading.
I used the apache isis CommandExexuteIn:Background action attribute. However, I got an error
"Not an (encodable) value", this is an error thrown by the ScalarValueRenderer class.
This is how my method looks like:
#Action(semantics = SemanticsOf.SAFE,
command = CommandReification.ENABLED)
commandExecuteIn = CommandExecuteIn.BACKGROUND)
public Blob exportViewAsPdf() {
final Contact contact = this;
final String filename = this.businessName + " Contact Details";
final Map<String, Object> parameters = new HashMap<>();
parameters.put("contact", contact);
final String template = templateLoader.buildFromTemplate(Contact.class, "ContactViewTemplate", parameters);
return pdfExporter.exportAsPdf(filename, template);
}
I think the error has something to do with the command not actually invoking the action but returns the persisted background command.
This implementation actually worked on the method where there is no return type. Did I miss something? Or is there a way to implement background command and get the expected results?
interesting use case, but it's not one I anticipated when that part of the framework was implemented, so I'm not surprised it doesn't work. Obviously the error message you are getting here is pretty obscure, so I've raised a
JIRA ticket to see if we could at least improve that.
I'm interested to know in what user experience you think the framework should provide here?
In the Estatio application that we work on (that has driven out many of the features added to the framework over the last few years) we have a somewhat similar requirement to obtain PDFs from a reporting server (which takes 5 to 10 seconds) and then download them. This is for all the tenants in a shopping centre, so there could be 5 to 50 of these to generate in a single go. The design we went with was to move the rendering into a background command (similar to the templateLoader.buildFromTemplate(...) and pdfExporter.exportAsPdf(...) method calls in your code fragment, and to capture the output as a Document, via the document module. We then use the pdfbox addon to stitch all the document PDFs together as a single downloadable PDF for printing.
Hopefully that gives you some ideas of a different way to support your use case
Thx
Dan

Optimized Way for Data Parameterization in TestNG

I am trying to create a framework using selenium and TestNG. As a part of the framework i am trying to implement Data Parameterization. But i am confused about optimized way of implementing Data parameterization. Here is the following approaches i made.
With Data Providers (from excel i am reading and storing in object[][])
With testng.xml
Issues with Data Providers:
Lets say if my Test needs to handle large volumes of data , say 15 different data, then i need to pass 15 parameters to it. Alternative , if i try to create a class TestData to handle this parameters and maintain in it , then for every Test there will be different data sets. so my TestData class will be filled with more than 40 different params.
Eg: In a Ecom Web site , There will be many different params exists like for Accounts , cards , Products , Rewards , History , store Locations etc., for this we may need atleast 40 different params need to declared in Test Data.Which i am thinking not a suggestable solution. Some other tests may need sometimes 10 different test data, some may need 12 . Even some times in a single test one iteration i need only 7 params in other iteration i need 12 params .
How do i manage it effectively?
Issues with Testng.xml
Maintaining 20 different accounts , 40 different product details , cards , history all in a single xml file and configuring test suite like parallel execution , configuring only particular classes to execute etc., all together will mess the testng.xml file
So can you please suggest which is a optimized way to handle data in Testing Framework .
How in real time the data parameterization , iterations with different test datas will be handled
Assuming that every test knows what sort of test data it is going to be receiving here's what I would suggest that you do :
Have your testng suite xml file pass in the file name from which data is to be read to the data provider.
Build your data provider such that it receives the file name from which to read via TestNG parameters and then builds a generic map as test data iteration (Every test will receive its parameters as a key,value pair map) and then work with the passed in map.
This way you will just one data provider which can literally handle anything. You can make your data provider a bit more sophisticated by having it deal with test methods and then provide the values accordingly.
Here's a skeleton implementation of what I am talking about.
public class DataProviderExample {
#Test (dataProvider = "dp")
public void testMethod(Map<String, String> testdata) {
System.err.println("****" + testdata);
}
#DataProvider (name = "dp")
public Object[][] getData(ITestContext ctx) {
//This line retrieves the value of <parameter name="fileName" value="/> from within the
//<test> tag of the suite xml file.
String fileName = ctx.getCurrentXmlTest().getParameter("fileName");
List<Map<String, String>> maps = extractDataFrom(fileName);
Object[][] testData = new Object[maps.size()][1];
for (int i = 0; i < maps.size(); i++) {
testData[i][0] = maps.get(i);
}
return testData;
}
private static List<Map<String, String>> extractDataFrom(String file) {
List<Map<String, String>> maps = Lists.newArrayList();
maps.add(Maps.newHashMap());
maps.add(Maps.newHashMap());
maps.add(Maps.newHashMap());
return maps;
}
}
I'm actually currently trying to do the same (or similar) thing. I write automation to validate product data on several eComm sites.
My old method
The data comes in Excel sheet format that I process slightly to get in a format that I want. I run the automation that reads from Excel and executes the runs sequentially.
My new method (so far, WIP)
My company recently started using SauceLabs so I started prototyping ways to take advantage of X # of VMs in parallel and see the same issues as you. This isn't a polished or even a finished solution. It's something I'm currently working on but I thought I would share some of what I'm doing to see if it will help you.
I started reading SauceLabs docs and ran across the sample code below which started me down the path.
https://github.com/saucelabs-sample-scripts/C-Sharp-Selenium/blob/master/SaucePNUnit_Test.cs
I'm using NUnit and I found in their docs a way to pass data into the test that allows parallel execution and allows me to store it all neatly in another class.
https://github.com/nunit/docs/wiki/TestFixtureSource-Attribute
This keeps me from having a bunch of [TextFixture] tags stacked on top of my script class (as in the demo code above). Right now I have,
[TestFixtureSource(typeof(Configs), "StandardBrowsers")]
[Parallelizable]
public class ProductSetupUnitTest
where the Configs class contains an object[] called StandardBrowsers like
public class Configs
{
static object[] StandardBrowsers =
{
new object[] { "chrome", "latest", "windows 10", "Product Name1", "Product ID1" },
new object[] { "chrome", "latest", "windows 10", "Product Name2", "Product ID2" },
new object[] { "chrome", "latest", "windows 10", "Product Name3", "Product ID3" },
new object[] { "chrome", "latest", "windows 10", "Product Name4", "Product ID4" },
};
I actually got this working this morning so I know now the approach will work and I'm working on ways to further tweak and improve it.
So, in your case you would just load up the object[] with all the data you want to pass. You will probably have to declare a string for each of the possible fields you might want to pass. If you don't need that particular field in this run, then pass empty string.
My next step is to load the object[] by loading the data from Excel. The pain for me is how to do logging. I have a pretty mature logging system in my existing sequential execution script. It's going to be hard to give that up or setting for something with reduced functionality. Currently I write everything to a CSV, load that into Excel, and then I can quickly process failures using Excel filtering, etc. My current thought is to have each script write it's own CSV and then pull them all together after all the runs are complete. That part is still theoretical right now though.
Hope this helps. Feel free to ask me questions if something isn't clear. I'll answer what I can.

How do run each browserdriver based on enum list value?

I am using the code found in the first answer on this page: Click Here
I an able to run this successfully and choose the browser by changing environment USED_DRIVER line for a number of different browsers.
I was wandering if it is possible to run a test runs it through each case once before finishing, i.e. so that it has been tested on each of the selected browsers once I have had a go at using for, and if but havnt been very successful.
Example Test
driver.get("calc.php");
driver.findElement(By.name("firstnumber")).sendKeys("2");
Thread.sleep(500);
driver.findElement(By.name("secondnumber")).sendKeys("2");
Thread.sleep(500);
driver.findElement(By.name("Calculate")).click();
Thread.sleep(500);
driver.findElement(By.name("save")).click();
Thread.sleep(500);
I believe what you are asking for is to run a single test multiple times, once for each browser.
There are different ways you can do this...I'll start with the simplest (but hardest to maintain in the future, so make sure you understand each choice before choosing):
Solution 1: The simplest way would be to put a for loop around your test. You will have a List of different WebDrivers that the tests will run on. It would look something like this:
WebDriver[] drivers = new WebDriver[]{firefoxDriver, chromeDriver};
for (WebDriver driver:drivers){
...test goes here.....
}
The problem with this method is that each test you run will have to have that for loop, and they all will create their own drivers.
Solution 2: You could have a central method call each of your tests. It would look something like this:
public void runTests(){
...create your drivers here (and the array)...
for (WebDriver driver: drivers){
runFirstTest(driver);
runSecondTest(driver);
}
}
public void runFirstTest(driver){
...code using driver goes here....
}
This solves the problem of having a for loop and creating driver instances in every test, but now, whenever you write a new test, you have to add it to this for loop.
Solution 3: Another solution exists, using a testing framework. The two most popular are TestNG and JUnit. I'm going to assume all of your tests are in the same class, but if you have multiple classes, you will want to have only 1 class have the #DataProvider
#DataProvider(name = "drivers")
public provideDrivers(){
...create drivers here...
return new Object[][]{{firefoxDriver},{chromeDriver},....};
}
#Test(dataProvider = "drivers")
public runTest(WebDriver driver){
...do stuff with driver here...
}
This solution will run every method that has #Test(dataProvider = "...") once for every driver you pass in. More information is here
If you have questions, feel free to comment. I will respond.

Connection between requirements and code in code

I am looking for simple way to connect information about requirement/release and source code.
The case is that developer should be able to find any artifacts created given release or CR in easy way.
The idea I have is to introduce some new annotation to mark any new class ( I am not sure if it is good for any new method) for example:
#ArtifactInfo(release="1.2" cr="cr123")
Do you have any other ideas? Maybe you use already something similar?
Take care,
Marcin
IMO the code is the wrong place for that kind of information.
Take a look at the imaginary code below.
class Authenticator {
login(String username, String password){
User user = retrieveUserFromDatabase(username);
throwIfWrongpassword(user, password);
verifyUserAge(user)
}
void throwIfWrongpassword(User user, String password){
//throws AuthenticationException if password is wrong
}
void verifyUserAge(User user){
//verify that user is above 18 or account is authorized by a parent
}
void biometricLogin(String username, BiometricImage bioimg){
User user = retrieveUserFromDatabase(username);
verifyBiometricImage(user, password);
verifyUserAge(user);
}
}
This is the result of a few requirements:
Users must authenticate to have acces to the system
Users can use biometric authentication instead on password auth
Underaged users must be authorized be parents or something like that.
All those requirements were added in different poins of time, on different versions of the software.
A class-level, or even a method-level annotation won't suffice to effectively map requirements to code.
You'd have to use a "line of code"-level annotation.
Of course, that's impractical.
The right way to do that is to follow a few best practices when using the source code repository and the bug tracker:
1) Every requirement corresponds to one or more issues on the bug tracker
2) Every commit message starts with a corresponding issue key, like "PROJ-123 - a nice feature"
3) When you do a release (meaning, incrementing your software version), you tell the bug tracker that those issues were fixed in that version.
If you need to know what requirements were implemented in what version, ask your bug tracker.
If you need to know all the code that was produced for a given requirement, ask your source code repository (filter commits by log message)
If you need to know what is the requirement for a given line of code, ask your source code repository. GIT and SVN have a "blame" command that will tell you, for a given file, for each line of code, who commited it, when, and the commit message (which will have the issue number if everyone on the team is a good boy) - So this will work as that hypothetical "line-of-code"-level annotation.
Using "commit hooks" can help you enforce rule 2) in an organization.
Maven has some degree of integration with JIRA and other bug trackers, and maybe it can help automate #3. But I haven't really used it like that. But if it doesn't do what you need, you can always ask for more :-)

Categories

Resources