Selenium Anti-Pattern – Using DefaultSelenium
I’m working with a Java client right now and am quickly re-remembering some anti-patterns for making your Selenium scripts in strong-typed languages. In Ruby you can run pretty fast and loose and have things running okay, in Java, not so much.
One thing I see is people using the DefaultSelenium class as provided by Se for establishing their connections to the Se-RC server. This is actually a really limiting move. Eventually your framework will have some user-extensions or other shortcut/convenience methods that you will want to have on the Se object itself. (Rather than messing with static methods and other things.)
What I recommend people do is create a class that extends DefaultSelenium and use that one instead.
<pre lang="java">package com.klient.gallery.selenium;
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.*;
public class KlientSelenium extends DefaultSelenium {
public KlientSelenium(String rcHost, int rcPort, String browserString, String baseURL) {
super(rcHost, rcPort, browserString, baseURL);
}
public void waitForLoadingFinished() {
new Wait("Timed out while waiting to load") {
public boolean until() {
try {
boolean visible = commandProcessor.getBoolean("isVisible", new String[] {"progressbar",});
if (visible == false) {
return true;
}
return false;
} catch (SeleniumException e) {
return false;
}
}
};
}
}
Here we have the the skeleton of a custom Se class. This was easy to do, but re-learning Interfaces took a bit of work. See, DefaultSelenium ‘implements’ the Selenium interface. Which to the non-Java trained people means that it provides a specific set of methods, and only those methods. I had hoped that it was the minimum set, but noooo.
Anyways, because of the way things work in Java, to get to your custom methods you have to do a bit of casting which is not the nicest way to do things visually (again, from my Python/Ruby bias), but it works.
<pre lang="java">// won't work
selenium.waitForLoadingFinished();
// will work
((KlientSelenium)selenium).waitForLoadingFinished();
Without the cast in there the ‘selenium’ object is constrained by the interface.
Even if you don’t have anything custom for now it is worth making the custom class sooner than later as you will eventually and changing scripts is a pain.