Reputation: 1257
I currently have a number of web UI tests which share different tests (for instance, the AccessOwnProfile
test and the AccessAdminMenu
test both derive from the Login
test.) So when I run the two separately in my suite, a new instance of WebDriver will be created for both tests, so the Login
test will be ran multiple times, because AccessOwnProfile
and AccessAdminMenu
both extend Login
test, like so:
public class AccessOwnProfile extends Login {
@Before
public void setUp() throws Exception {
super.setUp();
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
@Test
public void test() throws Exception {
super.test();
...
}
This is not good because if AccessOwnProfile
and AccessAdminMenu
are both used in my TestSuite
, Login
will be executed twice which is pointless. Ideally, I'd like to be able to only have to run the Login
test once.
This isn't necessarily difficult, I only need to remove the extends
in my test classes so every test is truly isolated. However every test still expects to pick up where the previous one left off.
So I need to be able to keep the same instance of WebDriver for my entire TestSuite
.
Basically what I want to do is to be able to run multiple JUnit tests that pick up from where the other left off, on the same browser instance. Basically, after a test, I wouldn't close the web browser and open a new one for the new test as I do right now. I'd just reuse the browser that's already opened.
I'm not entirely sure how to do this and where this would be configured. I cannot pass a webdriver instance to my test classes in my TestSuite
.
From my previous tests, it appears to me that each new instance of WebDriver keeps the same session from the previous one, meaning I could easily close the browser after every test and open it again for following tests. However I don't know if this is a reasonable expectation. It also means I can't just pick back up easily from the previous test's ending page, which is a bit of a problem. The only way I can think of how I would do this would be to write the current page URL into a temp file on tearDown()
, and then, on the following test's setUp()
, open that file and access the saved URL.
There has to be a better way.
As it stands, I have divided different tests into multiple smaller tests so I can reuse code.
Imagine a EditAvatar
test. You need to login and access your profile first.
Imagine a EditUsername
test. You need to do that as well.
Instead of repeating those tasks which can be tests in and of themselves, I made them separate tests that these two tests inherit from.
The way i put it in place is that:
AccessOwnProfile
extends Login
;EditAvatar
extends AccessOwnProfile
;EditUsername
extends AccessOwnProfile
;and so on
That means in my Test Suite, if I run EditUsername
and EditAvatar
:
Login
will be played twiceAccessOwnProfile
will be played twiceTo save on time I'd like to be able to use just one instance of the browser for the entire suite. That way I don't have to Login
all over again for every test that requires access to a user panel for instance, because all I'll have to do is run my Login
test once, and then I'm logged in for the rest of my TestSuite, I don't have to worry about repeating that particular task for each test.
Upvotes: 1
Views: 731
Reputation: 86
I faced the exact same problem as you. Closing and reopening the WebDriver for every test was a no-go for me. So I digged the internet and I found a solution by Tarun Lalwani (Scroll down to Attempt 3 for the solution).
He basically found a way to reuse the WebDriver by extracting its drivers (e.g. GeckoDriver, ...) URL and SessionID which than can be used to create a new instance of a RemoteWebDriver that communicates with the same previous driver.
In addition, if you are using ChromeDriver this said solution might not work because Chrome is not using W3C Codec (as user2590117 stated) like the RemoteWebDriver in the above solution. So just follow the fix of user2590117 and you should be good to go.
To pass the drivers URL and SessionID between tests, I serialized both using jackson with some custom JsonSerializer objects, which worked just fine and which I unfortunately can't share because I did it for work.
Upvotes: 1