April 7, 2020
How to write reliable test automation in Selenium using page object model

How to write reliable test automation in Selenium using page object model


So today let’s talk about writing selenium
test automation. Selenium is a great tool for writing your tests in. However, there
are some pitfalls that you can encounter early on if you do not structure your tests correctly.
Today I am going to show you some of the best ways to structure your tests so that they
are maintainable, repeatable, and reliable. Early on you might notice that when you write
tests they might work for a little while, but break or the page may change a little
bit and then you end up having to do a lot of refactoring. With these tricks I am using
today you’ll find that you’ll be able to write them in such a way they are able to be refactored
a lot easier. Some of the things I am going to show you today are going to help your tests
from becoming flaky the worst kind of tests are the ones that will basically fail for
no particular reason. That can become more and more common now with a lot of the asynchronous
operations that pages will do nowadays so I am going to show you how to use dynamic
waits and other nice little things to keep your tests running reliably. The other thing
people run into with their tests suites is that the web page will change over time and
they have to spend a lot of time maintaining their tests and updating them. If you go ahead
and write your tests in the right way you should notice that they are easy to change.
So let’s get into that now. So as a demo today I am going to surf over to the B&H photo video
website and they have some functionality here to show you that there is free expedited shipping
to wherever they think you live. So that can also be changed using this shipping location
dialog and reentering your zip code so I am going to write some tests to verify that that
functionality works as expected. Ok so for our first test let’s verify that the city
shown for the free expedited shipping is not a blank value. So let’s go over to our IDE
and setup for our test. I’m using Java and jUnit 5 so let’s create our first test decorator.
Let’s call this something descriptive like free shipping label city should not be blank.
Alright, now the other neat thing I’ve found, one of the headaches I used to have with Selenium
is having to setup your driver. Things like that. So, I found a package called Chrome
Driver Manager that all you have to do is go in here like this chromeDriverManager.getInstance().setup()
and it will pull your Chrome Driver for you and set it up automatically. So all we have
to do now is create our driver…equals new ChromeDriver. Alright, so that’s our wiring.
And now we can just go to our website. So driver.get let’s go to the bh photo website.
Ok. And once we’re there, we want to verify that the label right here…it’s a span actually…is
showing some non blank value, right? So, we know this is a span with a class that has
shippingDest on it. So let’s locate it. Alright so we are going to right an assertion here
that it’s not blank. So, oh. So let me go back a step here. Uhm, we are using Maven
so in our POM file for that web driver manager we just add this dependency to io.github.bonigarcia.
For WebDriverManager 1.7.0 and that will do all the magic for us on that. Next thing I
like to do is use assertJ assertions. They are very fluid. So that is this dependency
down there. Obviously you need your selenium java dependency. So let’s hop back over. So
now we have access to assert that. Ok so let’s assert that that span element. So driver.findElement
by.css selector. Ok we know it is a span. Dot ship dest right. I like to use IDs where
possible, but when we don’t have them this works too…not empty…let’s try that. Let’s
run our test. And it fails! Because we were not expecting it to be empty so we will start
with our first pattern with the dynamic waits. So, that element on that page is going to
load dynamically so it does start off by the time we get here…uhm…it’s going to be
an empty tag until it loads in later. So, we need to add a wait. To do that we can add
a new web driver wait. Ok and that takes the driver and how many seconds you want it to
wait. Let’s say 5, ok…and we are going to add an until condition. So it is going to
check, and by default it will check every half second until your conditions are met.
So my expected conditions is that it is not going to have some empty text. You might also
already notice that we are already duplicating selection code. Which we will refactor later.
Alright, so now we’ve got the web driver wait for 5 seconds until the text is not an empty
string. And then after that we’re going to assert that it’s not empty so kind of a weird
test because you know this is going to fail before this does, but this is just an example
of some dynamic waits. So let’s rerun this and see what happens. Alright so we’ve got
green. Our test passed. So to this point we’ve verified that the web page shows some non
blank value for the city, but now to write a more useful test let’s change zip code to
a city that we know and verify that that is what comes through so let’s create another
test declaration. @Test public void free shipping label city should show Fort Lauderdale for
33331 zip code. And I’m also going to change styles a little bit.I like writing comments
in a given, when, then format to uhm kind of organize my thoughts here as I go so before
we even write code. Let’s write some comments. So uhm given the landing page is loaded…when
I change the zip code to 33331…then the city should change to Fort Lauderdale. Alright
so we know how to setup our given again. We can just grab that from the test before. Now
that we’ve changed pages. We want to add a dynamic wait. Alright so now we just need
the zip code. So driver dot find element by dot css selector span ship dest. So now we
are actually going to click on that span. Then, once we’ve done that we need to change
the value in the zip input. So that’s an input called shipping zip input by it’s class. And
we are going to send the keys for the zip code. And lastly we are going to click the
submit button. Which is a div. With a class applied to it called shipping zip button.
So that is going to be another asynchronous operation. So if we were to assert on that
directly we are going to have a problem so to save time I’ll just copy and paste some
syncing code I’ve got. And why not move it up here instead…Alright, so we know we’re
there, and so now we can assert that driver dot find element by dot css selector span
dot ship dest dot get text is equal to Fort Lauderdale. When we run it let’s see if this
works. And it works. So I wouldn’t consider these tests written in such a way that they
are easily maintainable and there is a lot of duplicate code and things like that, right?
So let’s uh let’s go ahead and revise this a little bit. So, first thing, what I’d like
to see happen is that we have our driver declared once as a public static at the top of our
test class. Ok. And let’s start leveraging BeforeEach, BeforeAll, and AfterAll. So Iike
in my after alls to put the quit. So, uhm, that is where I am going to close my browser
after all runs. After All runs after all the tests have finishing running. And then the
before is where I do all of my wiring, right? So before class, right? That would run once
before all of the tests. Not each test run, ok? So that is where I am going to put my
Chrome driver manager dot get instance dot setup. And then instantiate my chrome driver.
In the before each that is up to you however you want to set your tests for the next run
so that it is in a predictable state so in this case I’m going back and refreshing the
b h photo video website. Seems like a good idea as well as waiting for the uhm value
not to be blank. And that should get us in a good state. Alright so this test is going
to away. That was from earlier. Let’s bring over our test cases and redesign them a little
bit. Ok, so we don’t need this. And we don’t need that. Driver get. And we don’t need the
wait ok so let’s change this to given I am on the landing page the shipping city should
not be blank. We can take out the driver dot quit line because that happens after all the
tests are run. It’s expensive to close the browser and reopen on each test so I tend
not to do that unless it’s necessary for the test scenario. In this case it is not. Ok,
uhm, and then here is another place we can get rid of some of the extra code.The tests
are already much simpler ok so here is this. We need to keep that for now. And we can get
rid of the driver quit. Alright so now we have a lot less lines. We can run both tests
at the same time. If these tests play nicely they should be able to run right after the
other without causing issue. And they do! Excellent! Perfect perfect perfect. Ok. So
now, we are going to want to refactor this so that if the page changes, some of the selectors
things like that, it gets reworked, we don’t need to go in here and change the css selector
all over the place. It’s kind of annoying. So, we’re going to create a package called
Pages and let’s create a landing page. In here we’ll have a driver and the landing page
takes the driver from your test and that’s where we can do some of this sync up code.
Alright so this is very important when you are doing things like multi-page tests when
you transition from one page to the next. I like to have a wait of some sort. You can
wait on the URL or maybe some lower element on the page especially when there is some
asynchronous load things present to make sure that they’ve loaded right? So in this case
we want to make sure that that city selector is no longer blank. So we are just going to
put that right in the page load. What I do is I’ll throw an exception if my tests aren’t
in the state I think they should be. So I throw an IllegalStateException in case the
landing page is not in the expected state. That get’s us setup on step 1. Now we are
going to want to define all the page elements in here so that I don’t have to have selectors
all over my test class and if something does change I just change here on the page in this
page class without having to do it in a million different test cases. So just refactor in
one place and we’ll be much better off. So we are going to create a public web element
called city span. And that is going to return driver dot find element by css selector span
dot let’s see what was that? That was span dot ship dest. Alright, and what else did
we use? We need the zip input. And lastly, we had the button to ok that. Stick that right
here. Alright so we have our three elements. We’ve got some sync code for the landing page
so let’s refactor yet again. Alright so now we are just going to create an instance of
the landing page in here. That’s going to float around. Public landing page landingpage.
So in here we’re going to call it. Actually, we should be doing it here. Landing page equals
new landing page driver. Ok so here once we create the new it is going to run that wait
code so that we know that the city element has loaded itself up, right? So we know we
are safe here. So after the gets in my case is where I put the instantiation of the different
page elements. And that is where I am going to have my sync code so I know that it’s safe
to move on and that the page is actually loaded. And that helps with the test being reliable.
So now that we have our landing page element instead of having to do all this. I can just
do landing page dot city span dot get text is not empty. Let’s rerun. And that’s still
passing. And let’s do that here too. A lot more readable so this is going to be zip input.
And landing page dot zip button. zip button. And lastly let’s change our assertion. landing
page dot get, whoops. Uh what was it…city span. Dot get text is equal to Fort Lauderdale.
Let’s rerun all these tests and make sure they still work. Alright, so there we go.
Uhm, so if any of these elements change instead of having to make the change in all those
places you saw me just refactor I can just change it here so if this changed to destina-TION
I can just make the change here and all of my tests would be automatically updated. And
that will cut back a lot on the time you have to spend maintaining your tests and with dynamic
waits it will make sure your tests are ready to run reliably and this is much better than
some sort of hardcoded sleep, right? So you could have just slept the test for 5 seconds
or something to wait for the conditions to match with what you were expecting, but you
are paying that penalty every single time even if it only takes 1 second or less to
load. So dynamic waits should always be used where possible. So using the page object model
pattern will allow you to write your tests in such a way that they are easily refactorable
and the dynamic waits will allow you to write reliable assertions on asynchronous content
which most of the web is nowadays. So I hope you found this video very useful this is a
bit of an intro tutorial. I hope to do more of these videos later. This is a getting start.
If you have any questions be sure to leave them in the comments section below. If you
found it useful please subscribe and like. I really appreciate it and thanks for watching.

13 thoughts on “How to write reliable test automation in Selenium using page object model

  1. Wow! Man! Finally!!! I have courses for automation and this topic is was cracking my head! It's the clearest explanation which I got! Thank you! Finally, I can finish my homework and it's clear English! P.S. I'm gonna share your video in QA community.

  2. Are you interested in teaching? I know automation courses in California where you can be work remotely. If you are interested, just let me know. Good luck.

  3. You really should make more of these videos. Though I knew the material – it would of been nice to find this a year or so ago. Simple and to the point. Seriously – make more automation vids

Leave a Reply

Your email address will not be published. Required fields are marked *