Closed hhoang closed 12 years ago
There are 2 issues here.
The first thing to note that is all tests are, and should be, independent of each other and that TestNG will, and should, run the tests in different orders on each run.
Your tests should be designed so that they can be run in any given order, and also that each test can be run on it's own without relying on any other test to setup state.
Specifically, you should not assume that when the addMerchant test runs that the loginBackOffice test has previously run and the app is now in a logged in state.
I would suggest put the delete cookies portion back in so that each test starts from a known base state each time even if a specific test fails and doesn't run to the end.
Secondly, your error is because you have not initiated the homePage page object in the 2nd test.
You could do this (if you can put a back door to your app to avoid having to login each time)
@Test public void addMerchant(){ HomePage homePage = new HomePage(driver); userPage= homePage.clickUsers(); userPage.clickAddUser(); userPage.addUser(); Assert.assertTrue(userPage.userIsAdded()); }
Otherwise try this ...
@test public void loginBackOffice(){ LoginPage loginPage = new BO_LoginPage(driver); HomePage homePage = loginPage.login(); Assert.assertTrue(homePage.isLoggedIn()); }
@Test public void addMerchant(){ LoginPage loginPage = new BO_LoginPage(driver); HomePage homePage = loginPage.login(); MerchantPage userPage= homePage.clickUsers(); userPage.clickAddUser(); userPage.addUser(); Assert.assertTrue(userPage.userIsAdded()); }
Hello,
Thank you so much for taking the time to write out your response. It helps a lot in gaining insight on how to write proper testcases.
In cases where I want multiple test cases for functions which are behind a login wall, is it general practice to create a backdoor for my automated testing?
I am still a bit confused. I understand the need to write isolated test cases, however, I feel like there are a lot of cases where this would be difficult because the tests need to be run in a specific order.
(If this is the wrong forum to ask these questions, forgive me, I can try asking on stackoverflow.)
For example: I'd like to be able to write test cases for a checkout process that i'm working on. The checkout has multiple phases. -The user clicks on their cart -User confirms the contents of their cart -User inputs payment information and clicks confirm -The application validates their information and returns the results.
In order to allow these tests to be run in any order, and to keep them isolated I would have to write testcases which go through each step one at a time before getting to the function I want to test.
It seems like this would result in a lot of redundant testing code, where for each step I want to test, I would have to test all the preceding functions first leading up to it.
If i wanted to write test cases with good code coverage, on bigger applications, it seems like the amount of tests that I'm performing would grow exponentially in size, since each test would require me to retest the preceding functions which have already been tested.
Thanks again for all your help
There is a fundamental difference is approach between scripting automated tests and executing manual exploratory tests.
My advice is to stop thinking about tests that need to be run in order, instead think about a suite of multiple tests that may all have several common setup steps. The computer is going to run those tests and it doesn't matter if it has to repeat itself, that's what it's for and if time to execute the suite is an issue then add more parallel threads to your suite.
An approach based on manual testing might look something like this
Test: Step A Check 1 Step B Check 2 Step C Check 3
When automating this your tests should look like this (IMO)
Test 1: Check 0
Test 2: Step A Check 1
Test 3: Step A Step B Check 2
Test 4: Step A Step B Step C Check 3
This approach will make your tests more robust and easier to debug and validate when / if they fail. It also means that you can make non-critical checks midway through your flow without blocking more critical checks later on if they fail. Example, in the manual style test above check 3 will not run if checks 1 or 2 fail.
My advice is to plan on having 1000's of tests and run your suite in parallel from the very start (i.e. as soon as you have 2 tests). Having lots of small focussed tests that each do one thing really well will be much easier to maintain in the long run than a small number of long tests that try and roll 10+ checks into one test.
There's no redundancy here as each check is only ever run once. You might have to use a lot of the same page object methods again and again while navigating your app but that will dependant of your UI and your users will need to do the same. If it's a problem for you think about your users, maybe your UI flow is overly complicated.
Just make sure you also only define each user action within your page objects once and again there's no redundancy. You're not retesting anything, your just reusing action methods that interact with your UI in multiple tests.
Get in touch if you need anymore help or check my blog http://iainrose.tumblr.com/
With regards to bypassing the login wall take a look at this talk by Santi @ Saucelabs which I found helpful
Another option is to move your login code into a method that is annotated as @Before
Something like this ....
@Before login() { .... login code goes here }
@Test test1() { ... test that expects a logged in state goes here }
That way you can extract anything you do over and over again as test setup and define it once.
My personal answer to hhoang: put your WebDriver object (Firefox or IE) as a static member of a utility class that you import into each of your page objects with a statement like : "import static com.domain.MyUtilities.*;" . Then, put a static getDriver() method in that class that is able to get the driver. Then, in each of your significant utility methods, such as your login method, which could/should be a member of the utility class, start the method with a statement like this: "driver = getDriver();" . There are lots of ways to do this, but I am trying to address your original issue of losing your pageobject instance (or driver instance) between tests...
That's a valid approach but my concern would be that it opens the door to having an overloaded util classes that do all kinds of various tasks rather than having the login method belong to the login page pageobject.
I'm not certain I fully understand the purpose of making a specific IE or FF webdriver object a static member of another class but wouldn't that prevent you from running the same tests across multiple browsers? Correct me if I'm mistaken, I'm no Java guru by any means.
I also haven't seen the stack trace on the original exception but I'm willing to bet it was on the homepage object rather than the driver object.
Wow, thanks django and iainrose for both your help.
I'm a college student interning as a QA and I'm stil figuring things out, so I apologize for my ignorance in these matters. (Testing isn't covered so much in our course curriculum, so i've been stumbling along trying to figure things out.)
The youtube video you linked me to is exactly what I was looking for and both your responses have given me a lot of ideas on how to proceed. It's great to see different techniques, so this discussion has been very enlightening for me.
Thanks again for taking your time to write out insightful answers!
No worries. You'll quickly learn that there is no right or wrong in testing. Don't say 'QA' but that's another story :)
Good luck and shout out if you ever need more help
I am working on a WebDriver testing template that shows an example of browser re-use . There are multiple ways to handle browser re-use, but this method uses the static WebDriver I mentioned above and uses a Gradle build script to run the tests. This is still a work in progress though and I haven't yet implemented an example of a page object but I will soon: https://github.com/djangofan/WebDriverTestingTemplate
Hi, I was looking to try out PageObjects with selenium to do some automated testing for my webapp, but I'm running into trouble getting the pageobjects to persist through different tests. The first test will work perfectly, but when I try to use the pageobject on one test to continue testing another portion of my webapp, i get errors.
So I have a test which will login to my webapp, once it's logged in, I want to be able to try adding a user. Inside the basetest class, I've tried removing the deletecookies portion. But I'm still getting nullpointer exceptions when it goes to the second test.
LoginPage loginpage; HomePage homepage; MerchantPage userPage; @test public void loginBackOffice(){ loginPage = new BO_LoginPage(driver); homePage = loginPage.login(); Assert.assertTrue(homePage.isLoggedIn()); }
@Test public void addMerchant(){ userPage= homePage.clickUsers(); userPage.clickAddUser(); userPage.addUser(); Assert.assertTrue(userPage.userIsAdded()); }
Any suggestions? Thanks again for writing this up, it's been very helpful so far in understanding pageojbects.