I'm following page object design pattern for Selenium automation and I can guess that many people store locators in .properties file and access them in code. It seems great to keep locators at separate place.
Since, I haven't work on any big project for Selenium automation, I would like to know thoughts on following so that I can avoid problems that might raise in future:
Is storing locators in properties file helpful in big projects(where test cases are more than 1000 or so)?
a) If not helpful in big projects, what are the difficulties that make us not to store locators in properties file?
b) If it's helpful, what are the precautions if that are taken makes job easier?
Is storing locators in page class itself is best way in comparison with properties file?
I would argue storing the files in the page class itself. Loading from properties file would incur additional overhead or parsing a large file. Maintaining such a file would also be harder, even with a good tool support you would be forced to use CTRL + F more than you should.
Even on a more conceptual level it feels wrong. A good fit for storing in properties files are configurable parameters, and especially the ones that are good candidates to be tweaked in runtime.
Locators don't have this nature. If the benefit you're seeking is declaring in a central place you should instead use dedicated constant class, which will give you much better refactoring options.
I would definitely agree with #Master Slave. The main purpose of selenium is to make the UI testing easier. Storing locators in the property file is cumbersome and additional overhead plus a nightmare for refactoring. One of the main reasons why the PageObject is popular is because it's ability to map elements with a very intuitive way
#FindBy(name="q")
private WebElement searchField;
#FindBy(name="btnG")
private WebElement searchButton;
It's just not only more readable but also far easier in case of refactoring and debugging. And, when something goes wrong on the page or changes there is a KNOWN place you go to change and you know where it is!
There are two basic ways:
1) Using FindBy annotation
#FindBy(xpath = "//*[#class = 'stackoverflow']")
private WebElement question;
2) Using By / WebElement class in the method structure
By stackoverflow = By.xpath("//*[#class = 'stackoverflow']");
WebElement stackoverflowElement = getDriver().findElement(stackoverflow);
And I completely agree with #Saifur and #MasterSlave.
I agree for the small projects with one running environment. Lets assume we have the project runs on two environments like Test and Production. Assume that in Test the locators are changed, then if you want to change code that will work properly in the both cases you should go to the branch. In case if locators placed in the property file you just change the file belongs to the environment.
I am not against storing locators in any format - either properties,INI, XML or xls as long as each file is small and manageable.
I think, as we are talking about 1000 test cases or more, for global variables [like URL, port number, username, password, email ] which are used only once, shall be stored in a separate global_variables file. Locators for EACH page can be stored in SEPARATE files. If one files is maintained for each page then locators are manageable. Pages will import ONLY file which is needed.
Clearly this approach creates more number of properties files as number of pages. This can be bettered by creating single file for related module or feature pages. Anyways as user we need to balance between less but huge locator file or more but smaller manageable locator files.
I am working on a similar strategy, where I need to decide which locator strategy is the best. What would be the best place to store the locators.
For code / property files, I have the following cons:
Time consuming to change the value of a single locator
Having stale locators/elements in the code
Makes the code bulky
Running tests on pre-prod and prod environment with different locators, results in creation of branches and duplication of code.
However, I am more inclined towards storing locators in a separate database and enabling its usage through a dashboard. I also feel this is very subjective to how your automation framework is setup. For a large scale framework, having over 1000 tests, having them separate makes more sense.
Related
Im building an automation framework in selenium using the Page Object Design Pattern.
Following are some of the data that Im using and where i have stored them
PageObjects (xpath, id etc) - In the Page Classes itself
Configuration Data (wait-times, browser type , the URL etc) - In a properties file.
Other data - In a class as static variables.
Once the framework starts growing it would be hard to store all the data it would be hard to organize the data. I did a some research on how others have implemented the way they store data in their framework. Here is what I found out,
Storing data (mostly page objects) in classes itself
Storing data in JSON
And some even suggested storing data in a database so that it would reduce reading times
Since there are lot of options out there, I thought of getting some feedback on what is the best way to store data and how everyone else has stored there data.
JSON or Any temp data storage is the best option as it is a framework and the purpose of it is to reuse for different projects.
I don't see any problem with the way you have stored your data.
Locators (by POM definition) should be stored in the page objects themselves.
Config data can be stored in some sort of config file... whatever you find convenient. You can use plain text, JSON, XML, etc. We use XML but that really comes down to personal preference.
I think this is fine also.
The framework doesn't really grow, the automation suite does. As long as you keep the data stored in the 3 places above consistently, I think you should be fine. The only issue I've run into with this approach is that sometimes certain pages have a LOT of functionality on them so the page objects grow quite large. In those cases, we found a way to divide the page into smaller chunks, e.g. one page had 22 tabs, each consisting of a different panel. In that case, we broke the page object into 22 different class files to keep the size more manageable and then hooked them all back into the main page as properties, e.g. mainPage.Panel1.someMethodOnPanel1();
I advice using Interfaces for each device type to store multiple type selectors, example:
import static org.openqa.selenium.By.cssSelector;
import static org.openqa.selenium.By.linkText;
import static org.openqa.selenium.By.xpath;
public interface DesktopMainPageSelector {
By FIRST_ELEMENT = cssSelector("selector_here");
By SECOND_ELEMENT = xpath("selector_here");
By THIRD_ELEMENT = id("selector_here");
}
than, just implement these selectors from whatever you need them.
You can also use enums with for a more complex structure.
I found this as best solution, because its easy to manage large numbers of selectors
Background
I am developing a new approach to automated testing using Selenium/TestNG/POM. So far, we have very promising results and automated large parts of our regression testing.
Now, we came to the step of expanding our test set by parametrizing them. We have end2end flows defined over multiple pages, where the pages are modeled into page objects. Most of these pages are forms, and in the end we get a resulting product/report that combines all the information.
Now my problem statement
We want to use Excel sheets so our business analysts can input the parameters and the expected values. But I am struggling to find a good way to structure the sheets. The naive approach would be to have a column for every parameter, and a line for every test case. A slightly better approach would probably be to use a different sheet for each page object, in a workbook, having a different workbook for each flow.
But my fear is that, by doing this, we are undoing all the good the POM brings us. If we need to change something (add a field in one of the screens for example), we need to regenerate all the excel sheets, or at least manually update each one. This is not that much better than having to update each scenario. In fact, we probably still have to edit all the scenario's (for example, if the new field is "name", add everywhere a "fillName('John')" step.
Is there a better way? Or is the manual work unavoidable? Or am I implementing POM incorrectly if I still need to adapt most scenarios everytime I need to add a field?
Trying to create yet another solution which use Excel as page object source you are bringing youself back to stone age. Use modern frameworks to handle Page Objects issues e.g. JDI with elements typification or Selenide wich provides more concise way.
I'm new to testing and trying to automate an OBIEE Dashboard application using Selenium Webdriver with Java. But, the problem is, the object identifiers I'm using (class, xpath, etc.) are dynamically generated, which leads to failure of my test case. Is there any way to overcome this? The scope of my test case is limited to testing the UI only.
My advice? Consider if you really, really, need to be using Java/Selenium approach.
A lot of OBIEE testing is better done at the logical layer using nqcmd or ODBC calls into the BI Server. If you really need to test the front end then visual testing is a generally more successful approach. The new Baseline Validation Tool covers both of these.
You can read more detail here:
http://www.rittmanmead.com/2014/01/automated-regression-testing-for-obiee/
http://www.rittmanmead.com/2014/05/visual-regression-testing-of-obiee-with-phantomcss/
http://www.slideshare.net/themoff/smarter-regression-testing-for-obiee-ukoug-15
https://www.youtube.com/watch?v=gMrspsqW0qM
You have to adjust the Generated XPaths as they may be not accurate.
for Example: You want to select this Div
<div class='blueBtn'>Click Me</div>
the XPath generated will be //div[#class='blueBtn']
This may select the first one but if this div is repeatable under another.
You may need to adjust the XPath to select what exactly you want.
So we may be adjust it to be //div[#class='blueBtn' and position()='2']
It's recommended to use the IDs of the elements as they are granted to be unique.
I hope this could help.
For many projects I have worked on, programming teams work with the style of placholding every piece of static text in an xhtml file into a properties file. For example:
xhtml=
...
<h1>${messages.resourceBundle['key.to.static.text.placeholder']}</h1>
...
messages.properties=
...
key.to.static.text.placeholder=This will be the heading for this page only
...
Would anybody be able to explain what the advantage in this is?
So far, I can only see the following disadvantages:
making changes to any xhtml file requires you to hunt for the correct .properties file, and then the individual property to make the change to
if others have re-used properties, then deleting them becomes tricky as you have to be certain no other page is referencing the property, therefore after several change request rounds, properties files become large with redundant properties
if there are 1000 xhtmls, there will be 1000 .properties files to load, which is more cycles on the cpu to load and inject static pieces of text
if your using WebFlow and have flows that pass into other flows, properties have to be duplicated, meaning that sometimes you must place the same property in many different properties files to render correctly
hard to read code; if you know you want to work on the text 'This will be the heading for this page' only, you'll need to work out where that is on the xhtml from the property files first - you can't simply look at the xhtml and see clearly how the content will be laid out once rendered.
The only advantages I can see are text reuse and possibly html escaping.
Apologies if its coding 101, but I've had a hunt around Google and can't find the reasoning to the pattern.
Many Thanks
This is a common practice for internationalizing content.
You create one property file per language (or locale) and use a dynamic way off resolving which one to load depending on the context. (e.g. Language HTTP header the browser sends).
It is arguably more flexible than providing 1 jsp file per language, and can still deal with complex cases where plurals or stylistic differences might change the way you write localized text.
This is a standard JDK feature, lookup resource bundles.
You do not have to build 1 file per jsp (maybe your framework works this way?), although doing so can help the person writing the translation.
Writing a test I expect the tested method to return certain outputs. Usually I'm checking that for a given database operation I get a certain output. My practice has usually been that of writing an array as a quick map/properties file in the test itself.
This solution is quick, and is not vulnerable to run-time changes of an external file to load the expected results from.
A solution is to place the data in a java source file, so I bloat less the test and still get a compile-time checked test. How about this?
Or is loading the exepected results as resources a better approach? A .properties file is not good enough since I can have only one value per key. Is commons-config the way to go?
I'd prefer a simple solution where I name the properties per key, so for each entry I might have a doc-length and numFound property value (sounds like the elements of an xml node)?
How do you go about this?
You must remember about maintaining such tests. After writing several web services tests with Spring-WS test support I must admit that storing requests (test setup) and expected responses in external XML files wasn't such a good idea. Each request-response pair had the same name prefix as test case so everything was automated and very clean. But still refactoring and diagnosing test failures becomes painful. After a while I realized that embedding XML in test case as String, although ugly, is much easier to maintain.
In your case, I assume you invoke some database query and you get a list of maps in response. What about writing some nice DSL to make assertions on these structures? Actually, FEST-Assert is quite good for that.
Let's say you test the following query (I know it's an oversimplification):
List<Map<String, Object>> rs = db.query("SELECT id, name FROM Users");
then you can simply write:
assertThat(rs).hasSize(1);
assertThat(rs.get(0))
.hasSize(2)
.includes(
entry("id", 7),
entry("name", "John")
)
);
Of course it can and should be further simplified to fit your needs better. Isn't it easier to have a full test scenario on one screen rather than jump from one file to another?
Or maybe you should try Fitnesse (looks like you are no longer doing unit testing, so acceptance testing framework should be fine), where tests are stored in wiki-like documents, including tables?
Yes, using resources for expected results (and also setup data) works well and is pretty common.
XML may well be a useful format for you - being hierarchical can certainly help (one element per test method). It depends on the exact situation, but it's definitely an option. Alternatively, JSON may be easier for you. What are you comfortable with, in terms of serialization APIs?
Given that you mention you are usually testing that a certain DB operation returns expected output, you may want to take a look at using DBUnit:
// Load expected data from an XML dataset
IDataSet expectedDataSet = new FlatXmlDataSetBuilder().build(new File("expectedDataSet.xml"));
ITable expectedTable = expectedDataSet.getTable("TABLE_NAME");
// Assert actual database table match expected table
Assertion.assertEquals(expectedTable, actualTable);
DBUnit handles comparing the state of a table after some operation has completed and asserting that the data in the table matches an expected DataSet. The most common format for the DataSet that you compare the actual table state with is probably using an XmlDataSet, where the expected data is loaded from an XML file, but there are other subclasses as well.
If you are already doing testing like this, then it sounds like you may have written most of the same logic already - but DBUnit may give you additional features you haven't implemented on your own yet for free.