Archive for the ‘webrat’ tag
In the first part of this article it was shown how to use CSS selectors for matching elements on complex web pages. But selectors are not the only way of matching HTML elements, Webrat also supports matching via XPath.
XPath matchers can be combined with CSS-selector matchers. This is really useful if not, for example, the content of an element should be matched but the element itself like in the following example. Here a form is used to display data as default value in its input elements. This can be the case in web applications in which data should be edited easily without additional clicks.
<div id="content"> <form> Label 1: <input id="entry_1" name="entry" value="Entry 1"/> Label 2: <input id="entry_2" name="entry" value="Entry 2"/> <input type="submit"> </form> </div>
Matching the default values of input elements with Webrat can look like the following lines of code. It is a nested combination of CSS-selector and XPath matching in order to have a readable error message if the actual output differs from the expected.
response.body.should have_selector("#content") do |content| content.should have_tag("form") do |form| form.should have_selector("#entry_1") do |input| input.should have_xpath("@value") do |value| value.should contain("Entry 1") end end end end
XPath matchers are currently not support by Webrat’s within() method and therefore cannot be used to limit the area on a web page where an action should take place, e.g. clicking of a link. They can only be used for evaluating the response of an action.
Popularity: 2% [?]
Writing feature, integration, or acceptance tests with Webrat is a lot easier with simple web pages than it is with huge pages which provide much content. It can get really annoying to find the correct links or buttons to click. The same applies for matching content elements on complex pages in order to evaluate whether a test case was successful or not, since the same content can appear on different areas of one web page. Both issues can escalate if the position of layout elements is variable like in A/B usability tests or if a front-end layout manager is used. CSS selectors can help to find a layout element on a web page independent of its position. In this article is demonstrated how CSS selectors can be used with Webrat.
In order to present the usage of CSS selectors with Webrat the following example is used. It shows a layout element called “content” which contains a table with two rows and each row provides the same options for its entry: Edit and delete.
<div id="content"> <table> <thead> <tr><th>Name</th><th>Options</th></tr> </thead> <tbody> <tr id="entry_1" class="odd"> <td>Entry 1</td> <td><a href="">Edit</a> <a href="">Delete</a></td> </tr> <tr id="entry_2" class="even"> <td>Entry 2</td> <td><a href="">Edit</a> <a href="">Delete</a></td> </tr> </tbody> </table> </div>
In order to find the corresponding delete link for one particular entry in the example, it is necessary to define a scope in which the link can be found. With Webrat this can be achieved with the within() method.
within "#entry_2" do |scope| scope.click_link "Delete" end
Within() does only support the following selectors which have been defined in W3C CSS level 1.
- Type selectors, e.g. “table”
- Class selectors, e.g. “tr.odd”
- ID selectors, e.g. “#content”
The nesting of within() calls is currently not supported which means that well chosen IDs in the HTML code are necessary for good tests.
In order to evaluate the response of the example after clicking the delete link of the second entry, the following statement would be sufficient, but in case the test did not work as expected it would return an error message which includes the content of the whole web page.
response.body.should_not contain("Entry 2")
Narrowing the part of the HTML code to the CSS selector which should be evaluated helps to get a more readable error message, since it only includes the selected part. In opposite to the the within() method have_selector() and have_tag() can be used nested, too. If a selector, e.g. in case of an error, is not available on a web page, an error message for the current scope is generated. This could be the whole page if the selector was the first one. Therefore it is recommended to start with a selector which is available even if an error occurs.
response.body.should have_selector("#content") do |content| content.should have_tag("tbody") do |table| table.should_not contain("Entry 2") end end
Using selectors in order to match elements on a web page has the disadvantage of a bigger dependency to the HTML code. Changing the name of a CSS selector can break test case. But this disadvantage should be insignificant compared to the achievement of error messages in which the actual problem is easily identifiable.
Popularity: 8% [?]
Webrat supports file upload in web forms with the method attach_file. Due to a lack of multipart form support for integration tests in Action Pack 2.0.2, this does not work with Rails 2.0.2.
It has been added in version 2.1., but for those who are still using 2.0.2, with the following code you can upgrade the particular part of Action Pack to 2.1. Just add it to your tests so that it overwrites the loaded Action Pack code.
Last year Bryan Helmkamp gave an interesting presentation on story-driven development at the Gotham Ruby Conference. In this presentation he showed a graph called the “web app testing pyramid” which displays the optimal proportion of different test types for web applications. The base of the pyramid contains fast low level test which can test small pieces of code like single algorithms while the pyramid’s peak represents the slowest tests which not only need a server with the running application but also a client with at least one started web browser.
The following graph shows the version of the pyramid we are using. We are not speaking of scenario tests like Bryan Helmkamp but of feature tests which are technically the same, though they are not written by developers for verifying code but by software testers to verify the functionality of features (see model-driven feature testing)
The fastest test type are unit tests. They are best suited for test-driven development (TDD) since they can easily be written by developers for verifying their code and for regression tests. Unit test should be used to test all parts of the code which don’t need additional resources like a database or plugins. Therefore unit tests should outnumber every other kind of tests.
All parts of the code that cannot be covered by unit tests for different reasons need to be tested by functional tests. These kind of tests allows to load extra resources like a database. They also can and should be used for TDD to verify that code is actually working.
Story-based tests – like Cucumber stories combined with Webrat – are really slow, hence they are not well suited to replace unit tests or functional tests but are a good supplement to your test portfolio since they can test on a higher level. They are furthermore the proper choice for feature tests which are supposed to verify all use cases of features by testing selected scenarios (see model-driven feature testing). The number of these scenarios should be lower than the number of functional tests since a lot more usage scenarios are possible than tested by feature tests.
Keeping the pyramid of web application testing in your mind should help you to optimize the run time of your tests by not loosing test coverage.
Popularity: 3% [?]