I have a class, which parses data from html page and turns it into a collection of String. Basically I have a URL of online-shop and I want to have a list of its items.
My class have the following signature:
public static List<String> getShopItems()
usually method returns very large List (4k items or more).
My question is, how can I test this method?
I think that I have to assert that returned list has correct size and contains all the items needed. But it would be very tedious to create List with 4k items and compare actual and expected Lists. Furthermore, items can change in the future, and my test will fail.
To sum it up, I can get actual data from my method getShopItems(), but I have no idea how to get expected data for assertion in test.
Thanks in advance.
You're testing data extraction from a webpage, not the webpage itself. As a consequence, you can (and should) make your own test page. This way, you can
reduce the list of needed items (I assume there aren't 4k different cases ?)
ensure the data won't change
Firstly, static methods like this are almost always a bad idea they make testing difficult.
Secondly, a Resource interface can really help testing cases like this. eg:
public interface Resource {
InputStream getStream();
}
Then you could refactor the class to be something like:
public class ShopItemProvider {
private final Resource resource;
public ShopItemProvider(Resource resource) {
this.resource = resource;
}
#Override
public List<String> getShopItems() {
try (InputStream in = resource.getStream()) {
return someFancyParseMethod(in);
}
}
}
Now, you've got the hook you need for testing. In a test case you can mock up an InputStream with just a few records in it, possibly sourcing a test file from the test classpath.
In production, the InputStream can come from a URL or File or maybe some production classpath resource.
A simple way is to keep the expected items in a local file. Then you can load the file contents, store all items in a sorted list and compare it to the (sorted) list of your shop items.
I normally split these tests up into 2 parts:
Testing the function thoroughly with basic / small data sets
Testing some basic properties with real data
You can achieve the different inputs by creating an extra parameter in the constructor (possibly optional), for example a location of a HTML file with test data. This allows you to inject fake data into the class.
Basic Test
Try to get 100% code coverage with this test, test for error handling, and for invalid data. Use several data sets for this test, and verify all output is correct.
Real data test
Try to use data from a real source, this could be the live site, but that might not always be available when running the test. Also it might fluctuate too much too write a proper unit test for. At least aim to write a test that will only fail if you have made an error writing the system (not if the data in the site changes). So most of the time I go for a data set that is saved earlier, so I can assert a bit more on the data set.
Now you have to be creative in your tests: try to assert for properties of the data. Examples could be (try to pick several!):
All prices in a price list must be positive.
There are no errors coming from your exhaustive error checking in the function.
Check the number of items. For the real data do this vaguely, for fake data do check the exact number.
separate method that gets the data from the method that parse the data so you can test different inputs (parse method should take a string or a stream rather than an url)
do very detailed tests using custom, small inputs. this should be your main testing part
you can take a snapshot of the webpage, save it locally and use it to test real data. update this file when page structure changes
last part is integration tests. connect to real webpage and check if your parser doesn't throw exceptions, if it still gives some reasonable output (like a list greater than 1k elements), check if page structure didn't change. don't test for exact list content as the page may change. also don't include integration tests into your unit tests as sometimes page may be down, network may be down etc
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
We have a test where basically we need to input a specific value in a web site and make sure another value comes out. The data of the input-output for this is stored in an XML file.
Now we can create a single Scenario that runs once and loops through, submitting each value however we run into some reporting problems, if 2 out of 100 pairs fail we want to know which ones and not just have an assertion error for the whole scenario.
We would get much clearer reporting using a Scenario Outline where all the values are in the examples table. then the scenario itself runs repeatedly and we can fail an individual set as an assertion error and have that kick back clearly in a report.
Problem: we do not want to hard code all the values from the xml into the .feature. it's noisy but also if the values change it's slow to update. we would rather just provide the XML parse it and go, if things change we just drop in an updated XML.
Is there a way to create dynamic examples where we can run the scenario repeatedly, one for each data case, without explicitly defining it in the examples table ?
Using Cucumber for this is a bad idea. You should test this functionality lower down your stack with a unit test.
At some point in your code, after the user has input their value, the value will be passed to a method/function that will return your answer. This is the place to do this sort of testing.
A cucumber test going through the whole stack will upwards of 3 orders of magnitude slower than a well written unit tests. So you could test thousands of pairs of values in your unit test in the time it takes to run one single cuke.
If you do this sort of testing in Cucumber you will quickly end up with a test suite that takes far too long to run, or that can only be run quickly at great expense. This is very damaging to a project.
Cuking should be about one happy path (The user can enter a value and see the result) and maybe a sad path (the user enters a bad value and sees an error/explanation). Anything else needs to be pushed down to unit tests.
The NoraUi framework does exactly what you want to do in your project. The NoraUi code is open source. If you have questions about this framework, you can post an issue with the tag "Question"
I am testing a new REST API for my company and I am splitting all of its methods into test suites with different parameter combinations as test cases. I also build negative suites with added assertions.
The suites are huge - they contain more than 100-150 test cases each. I need to be able to save all responses from the suites but in a single file. I found this article which works for me but not entirely http://gerardnico.com/wiki/jmeter/save_response_to_file - here I can add 'Save response to a file' listener but it creates separate files for each response. Basically this is useless, I can check them one by one from the result tree directly in the tool. I searched at multiple articles but I can't seem to find exactly the resolution of my problem.
Thank you in advance!
Add a JSR223 Listener to your Test Plan (on top level so it will collect the data from all the samplers, see Scoping Rules for more information)
Put the following code into "Script" area:
new File("responses.txt") << prev.getResponseDataAsString() + System.getProperty("line.separator")
When you will run the test next time you will be able to see responses.txt file in JMeter's "bin" folder containing all the responses
prev is a shorthand for SampleResult class instance, it provides programmatic access to parent sampler result so you will be able to read or even update certain parts like response code, body, message, overall success, etc. See Groovy Is the New Black article to learn more about using Groovy scripting in JMeter test.
I think Simpledatawriter can solve your problem if you use it at test plan level.
Right click on test plan
Add "Listener" >> Simple Data Writer.
Add a file name.
This will write all responses to a single file. (But it will has record the response code and message)
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.
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.