On this post, I will look at ways of improving Selenium scripts through code refactoring and starting to build a page object model. DEFINE TEST CASE I will use again the site of the Vancouver Public Library (http://www.vpl.ca). The test cases to be automated are related to the login page: SETUP
open the www.vpl.ca site
click on the MY VPL link
wait until the next page loads
click the LOGIN TO MY VPL page
wait until the next page loads
login does not work when using an invalid username and invalid pin
login does not work when using an invalid username and correct pin
login does not work when using an correct username and invalid pin
login does not work when using no username and no pin
login works with correct username and correct pin
GETTING READY The first thing to do is to inspect all HTML elements needed in the script in FIREBUG and identify XPATH expressions for finding them: MY VPL link //div[@class='box1']/h4/a LOGIN TO MY VPL button //div[@class='content']/a USERNAME field //input[@class='field_username text' and @name='name'] PIN field //input[@class='text' and @name='user_pin'] LOGIN button //input[@class='submit_button' and@name='commit'] ERROR POPUP //div[@class='top_message']/p As soon as the XPATH expressions are created, I will - start the Selenium server - create a new Java project in Eclipse - add the Selenium Server and Client JARs to the project - create a new test class - import the Selenium package to the class - add the setUp and tearDown methods to the test class for starting and stopping the Selenium server; these methods use the @Before and @After annotations - create an empty test method - run the project - if everything done before is correct, the project should run successfully It is the time now for adding the code to the test method for the test case: - the open, click, waitForPageLoad, selenium commands are used for navigating to the Login page - the type and click selenium commands are used for entering the username and pin values on the Login page - the click selenium commands is used for submitting the login page - the getXpathCount selenium command is used for checking if the login failed or succeeded Run the project again and confirm that there are no errors. The next step is to copy some of the code for all 5 login page verifications. The code is identical for the verifications with the exception of the values of the username and pin. Since some of the verifications need a correct username and pin, I import a new class that provides the correct username and pin values read from an xml file. Running the project again should not return errors.
CODE REFACTORING The following changes will be done to the code for refactoring:
1. split the test methods in 5 smaller test methods; each verification from the test case is done in a separate test method 2. since each test method takes 14 seconds to run, use @BeforeClass and @AfterClass instead of @Before and @After so that the selenium server is started once before all test methods run and stopped once after all test methods are executed; the test execution time for the methods should go down to 6 seconds because of these changes 3. create a new method for the code that opens the Login page: openPage() 4. create a new method for the code that types the username value: typeUsername(String usernameValue) add a parameter to the method for the username value 5. create a new method for the code that types the pin value: typePin(String pinValue) add a parameter to the method for the pin value 6. create a new method for the code that submits the login page: submit() 7. create a new method for the code that checks if the login was successful or not: countErrorPopups() 8. replace the code from each test method with the new refactored methods; add the values to the parameter of each method 9. Resolve any errors and run the project
PAGE OBJECT MODEL Since openPage(), typeUsername(), typePin(), submit() are all things that the Login page does, it makes sense to create a new class called LoginPage and move all refactored methods to it. By moving the methods to the LoginPage class, the test methods will no longer include any code that shows how the web page works. The LoginPage class will need a constructor that gets a Selenium parameter so that its methods can call Selenium methods.
After creating the LoginPage class, change the test methods by - creating a LoginPage object in every test method - prefix all refactored methods with the name of the LoginPage object Resolve any errors and run the code.
SUMMARY In this moment, a few things are accomplished: - Small and independent test methods - The test methods do not include information about how the site works - Easy to read and maintain test methods - I have created a Page Object class for the LoginPage. All details on how the LoginPage works are in the LoginPage class. If there are changes in the future for the Login Page, only the Login Page class needs to be modified.
I have started learning swimming last fall. My interest begun while watching people swimming on lanes in an outdoor pool. Those people were amazing. They were gliding through water slowly, efficiently, effortlessly and very quietly. They made swimming look so easy and simple. And beautiful ... So easy and simple that anyone may think that he can do it. By himself ..... So I started learning. How difficult could it be to move your arms and legs in the water? I realized shortly that I either don't do it properly or I don't understand how they do it. I persevered though and practiced more using a swimming training DVD as a guide. From the DVD, I learned that swimming is actually quite complicated as it consists in individual movements that need to be done in a well coordinated way. To swim well, I needed to understand how to rotate the body in the water, how to breath, how to syncronize the strokes with breathing, how to move my legs. Some of these things, especially breathing, are very difficult to get by yourself. My swimming got a bit better but very soon I stopped again making progress. So I hired a private instructor. This time, I committed money and time and worked towards my goal. After 3 months of practicing drills, repeating the same thing again and again, being frustrated of not doing it well, I finally started to make progress. I am currently at the point where I have the skills for swimming short distances and can move to the next phase of training. What is the connection between learning test automation and swimming? Test automation seems easy, especially when looking at other people doing it or when reading articles written by test automation tools vendors. How difficult can it be to record a script by using a site and then playing the script back? For sure, anyone can do it by himself .... So you try it by yourself first. Soon, you realize how limited is this way of "test automation" and how little you can do with it. So you persevere and learn about the need for a programming language. You read a programming book, learn some concepts and then come back to the test automation project. But just a programming language and a tool for recording scripts is again not sufficient. Reading more about test automation, you learn about other concepts like XPATH, browser DOM, code debugging, abstract layers, JUNIT, code refactoring, coding patterns, test driven development ..... But the swimming, sorry, test automation, was supposed to be easy and anyone can do it by himself!!! At this moment, the illusion is gone and you start thinking seriously what to do. You can persevere by yourself now that you see the territory to be explored or you can take your own swimming (test automation) instructor (course). One thing is clear: learning the new skill will not be quick, it will take time to get all the individual drills and integrate them but the end result is very rewarding… test automation code that is simple, efficient, elegant and effortlessly created ... You can get here with patience, perseverance and lots of practice. Same for swimming!