Les DSL et "fluent interface" pour les tests ASP.NET avec Selenium FluentSelenium
Content
Selenium and XPATH
Best practices for testing
FluentSelenium
Conclusion
Selenium introduction Selenium is a suite of tools to automate web app testing across many platforms
It is developed by ThoughtWorks and is available as an open source project
It includes
Selenium IDE : Firefox add-on that records clicks, typing, and other actions to make a test, witch you can play back in the browser
Selenium Remote Control : Run your tests in multiple browsers and platforms. Tweak your tests in your prefered language (C#, Java, Perl, PHP, Python or Ruby)
Uses XPATH as its web query language
Here's a web test written with selenium selenium.Open( "Forum/AllPosts.aspx" ); selenium.WaitForPageToLoad( "8000" ); selenium.Click( "newPost" ); selenium.WaitForPageToLoad( "8000" ); selenium.Type( "//*[contains(@id, 'txtAuthor')]" , "Luc" ); selenium.Type( "//*[contains(@id, 'txtSubject')]" , "Simple example of the library." ); selenium.Click( "//*[contains(@id, 'btnSavePost')]" ); selenium.WaitForPageToLoad( "8000" ); Assert .AreEqual( "Luc" , selenium.GetText( "//table[contains(@id, 'grdPosts')]//tr[2]/td[2]" ));
Xpath introduction XPath is a structred XML query language Example : get the node of the employee with ID 123456 Employees/Employee[@EmployeeID='123456'] < Employees > < Employee EmployeeID = " 123456 " > < LastName > Laporte </ LastName > < FirstName > Jacques </ FirstName > </ Employee > < Employee EmployeeID = " 654321 " > < LastName > Gendron </ LastName > < FirstName > Pierre </ FirstName > </ Employee > </ Employees >
Xpath introduction XPath is a structred XML query language Example : get the last name of the employee with ID 123456 : Employees/Employee[@EmployeeID='123456']/LastName < Employees > < Employee EmployeeID = " 123456 " > < LastName > Laporte </ LastName > < FirstName > Jacques </ FirstName > </ Employee > < Employee EmployeeID = " 654321 " > < LastName > Gendron </ LastName > < FirstName > Pierre </ FirstName > </ Employee > </ Employees >
Selenium and XPath on HTML Because HTML is an XML derivative, XPath can be used to locate nodes in a HTML web page Example : ask selenium to click on the Save button : selenium.Click(“//input[@id='btnSubmit']”); selenium.WaitForPageToLoad(“5000”); < html > < body > < form > < div >Hello World !</ div > < input type = " submit " value = " Save " id = " btnSubmit " /> </ form > </ body > </ html >
Complete simple web test with selenium
Content
Selenium and XPATH
Best practices for testing
FluentSelenium
Conclusion
Good testing practices
Test coverage
Test independance
Test clarity
Test coverage Should we aim for 100% coverage?
The trade offs
What does this mean? Integrated tests Unit tests Test coverage
Best practices of test coverage
Web tests are not cheap to write, maintain, or execute, don't strive for high coverage unless you need it
Favor coverage through testing of services and domain objects over UI testing
Use patterns that facilitate testing close to the UI layer such as MVC
Aim for coverage that gives you confidence in the quality of your deliverables
Test independance
Keep tests independent because:
They will be easier to fix
They will be easier to read
They will not be impacted by updates in other tests
Some things to consider...
For better independance consider using easily rebuildable dependencies:
Web server: Cassini
Database: Sqlite
For etxternal dependencies that cannot be relied on to be performant or predictable consider using a fake implementation.
Test Clarity
Tests need to be easy to read because they need to be maintained.
Tests are code also. Team code quality rules should also be applied to tests.
XPATH is dangerous, use it wisely Use ID-based queries when possible //*[@id = 'searchResultCount']
Avoid exessive XPATH steps When requiring further qualification in searches only add necessary qualifiers Favor //*[@id='searchResults']//li[1] Over /html/body//div[@id='searchResults']/ul/li[1]
XPATH queries are not clear Xpath expressions are the kind of literal who's meaning can be hard to decipher. Use constants. Favor selenium.GetText(SearchResultSummaryLocator); Over selenium.GetText( "//*[@id='searchResultsSummary']" );
Keep the test code clean
Always revise the tests for clarity.
Hard to read tests are hard maintain
Tests serve as application behavior documentation
The importance of language in tests
Who needs to understand your tests?
Know your target audience
Developers
Users
Testers
Technical writers
Write tests in your audiences language!
Use the appropriate level of abstraction
Unit tests
language of the code being tested
Integration tests
Language of the highest level of abstraction being tested
End-to-end tests
Users
Other actors (systems and services)
So what are DSLs? Domain-specific languages – are any language (API, programming or written) that uses a domain oriented terminology.
Nunit and MSTest use a test DSL
Nhibernate and Linq use query oriented languages
Users speak in the language of their needs and tasks
Programmers tend to speak in terms of technical jargon
In code this translates to the choice vocabulary used in class, method and variable names. Tests should use a DSL appropriate to the end user.
Content
Selenium and XPATH
Best practices for testing
FluentSelenium
Conclusion
Our solution FluentSelenium
Some examples shopper.Goto( "Shopping/ShopOnline.aspx" ); shopper.For(WelcomeMessageBox).ShouldSee( "Welcome to Shop-e online!" ); shopper.ShouldSee(FeaturedProductArea); shopper.For(FeaturedProductTitle).ShouldSee( "blank CDs (10)" ); shopper.For(FeaturedProductUnitePriceField).ShouldSee( "5.00$" );
... forumUser.Goto( "Forum/AllPosts.aspx" ); forumUser.For(addPostButton).Clicks(); forumUser.WaitFor(newPostPageLoadWait); forumUser.For(subjectTextBox).Enters( "Simple example of the library." ); forumUser.For(messagetTextBox).Enters( "blah" ); forumUser.For(savePostButton).Clicks(); forumUser.For(authorRequiredMessage).ShouldSee( "The author is required." );
The User The User class is the root of the DSL. All web test operations spawn from it. It is initialized as follows: var selenium = new DefaultSelenium (....); var forumUser = new User (selenium); Variables of type User should be named according to the role of the application user.
Pushing XPATH out of the tests FluentSelenium uses typed locator objects ElementLocator WelcomeMessageBox = ElementLocator .WithId( "welcome" ); InputLocator SearchCatalogText = InputLocator .WithId( "searchText" ); ButtonLocator SearchCatalogButton = ButtonLocator .WithId( "searchButton" ); ElementLocator FeaturedProductTitle = ElementLocator .WithXpath( "//*[@id='featuredProduct']//*[@id='title']" ); Locator types determine what operations are available with a “For” shopper.For(SearchCatalogText).Enters( "mouse" ); shopper.For(SearchCatalogButton).Clicks();
Application navigation Navigating to a specific address: goto shopper.Goto( "Shopping/ShopOnline.aspx" ); Navigating by clicking on links and buttons: click shopper.For(DiscountsButton).Clicks(); Waiting for page loading: WaitFor PageLoadWaitCondition SearchResultPageLoad = PageLoadWaitCondition .For( "Shopping/SearchResults.aspx" ); shopper.WaitFor(SearchResultPageLoad); Waiting for special conditions can be done by writing a custom implementation of IWaitCondition
Validating page content Presence or absence of an element shopper.ShouldSee(WelcomeMessageBox); shopper.ShouldNotSee(SearchResults); Content of an page element shopper.For(SearchResultsSummary).ShouldSee( "1 match found" ); Custom validation, any implementation of IContentValidator class AnyNumberValidator : IContentValidator { public void Validate( ContentTester contentTester) .... shopper.For(OrderNumber).ShouldSee(AnyNumber);
Testing table content Testing the content of a table row f orumUser.For(allPostsTable).Row(2).ShouldSee( "Luc" , "Hello" ); Jim Nothing Luc Hello Bob Goodbye Testing the content of a table column forumUser.For(allPostsTable).Column(1).ShouldSee( "Jim", "Luc", “Bob” ); Jim Nothing Luc Hello Bob Goodbye
Other table operations Checking cell content forumUser.For(allPostsTable).Row(2).Column(3).ShouldSee( "Present" ); Cells have content forumUser.For(allPostsTable).Row(2).Column(3).For(replyPostButton).Click();
Extending Custom implementations:
Synchronization conditions with IWaitCondition
Custom content validation with IContentValidator
Extending the User
Extend User and add new test methods
Use extension methods to add test methods to the User class
Content
Selenium and XPATH
Best practices for testing
FluentSelenium
Conclusion
FluentSelenium is...
A new open source project hosted on codeplex. You can download the source or contribute by visiting http://fluentselenium.codeplex.com
A simplified spin off of a framework developed for one of our clients. We expect to extend it with ideas and concepts that aren't yet implemented
These are the slides we presented at the 2009 Montr more
These are the slides we presented at the 2009 Montreal CodeCamp for our FluentSelenium test DSL. FluentSelenium demonstrates how it is possible to make test code cleaner by introducing appropriate test abstractions.
0 comments
Post a comment