Sunday, November 21, 2010
Monday, November 15, 2010
Extend Selenium Server with the help of Default Selenium
Default Selenium
DefaultSelenium is the base class that you instantiate early on in your test class to get the selenium object which you later use in almost every line of you test script.
.
.
Selenium selenium=new DefaultSelenium("localhost",4444,"*chrome","http://www.google.com/");
selenium.start();
selenium.open("/");
.
.
.
OR
/*Creates a new DefaultSelenium object and starts it using the specified baseUrl and browser string*/
setUp("http://www.imdb.com/", "*firefox");
selenium.open("/");
selenium.click("nb15go_image");
.
.
.
does that ring a bell?What do you mean by extending the default selenium?
Extending the default selenium means enhancing or customizing or modifying the existing features of selenium class. We are reusing the existing class after adding some enhancements so as to customize the existing features to our taste and requirement. Programming languages such as JAVA provide the facility of extending/modifying the behavior of a class without having to re-write the entire class. We can create a new class that inherits the attributes and methods of another. We don't need a copy of the original source code (as is the case with many other languages) to extend the usefulness of a class/library.
Why do I need to extend selenium?
If you want certain operations to be done every time before a step is executed then you would have to extend the default selenium. For example let’s say that you wish to wait 5 seconds after every step or you want to highlight the element before clicking on it or you want to record every step in log file or you want to poll for a element’s existence for a certain amount of time before performing an operation (click, type) on it. For all these to happen you would have to extend the default selenium class that you use in your RC test script.
Below is a simple example that demonstrates this concept. The class MySelenium extends the class DefaultSelenium. The methods click and type of the base class have been over-ridden in such a way that the target element (which is to be clicked on or typed into) is highlighted thrice before the click or type operation. The class UsingMySelenium by the means of a simple example demonstrates the usage of our extended class.
Class MySelenium
package seleniumExtention;
import com.thoughtworks.selenium.DefaultSelenium;
public class MySelenium extends DefaultSelenium{
public MySelenium(String seleniumSeverHost, int port,String browserString,String autURL){
super(seleniumSeverHost, port,browserString, autURL);
}
@Override
public void click(String target) {
try {
for (int i=0;i<3;i++){ i="0;i<3;i++){">
Class UsingMySelenium
package seleniumExtention;
import org.junit.Test;
import org.junit.BeforeClass;
import org.openqa.selenium.server.SeleniumServer;
import com.thoughtworks.selenium.SeleneseTestCase;
public class UsingMySelenium extends SeleneseTestCase{
public MySelenium selenium;
@BeforeClass
public void setUp() throws Exception {
SeleniumServer seleniumserver=new SeleniumServer();
seleniumserver.boot();
seleniumserver.start();
/*using the customized selenium class that we created earlier instead of the default selenium*/
selenium=new MySelenium ("localhost",4444,"*iexplore","http://www.google.com/");
selenium.start();
selenium.windowMaximize();
}
@Test
public void testSimpleGoogleSearch() throws Exception {
selenium.open("/");
selenium.waitForPageToLoad("5000");
selenium.type("q", "Aston Martin volante");
selenium.click("//input[@value='Google Search']");
selenium.waitForPageToLoad("5000");
selenium.click("xpath=/descendant::a[text()=' - The Cars']/em[text()='Aston Martin']/parent::a");
selenium.waitForPageToLoad("25000");
Thread.sleep(5000);
}
}
To make this work you need to do the following
1) Create a package seleniumExtention inside the java project.
2) Create the classes MySelenium & UsingMySelenium and copy paste the content as given above.
3) Run the testSimpleGoogleSearch() given in the class UsingMySelenium (right click Run As-->JUnit Test).
*Following jars need to be referenced
selenium-server.jar
selenium-java-client-driver.jar
junit.jar
good luck with this and keep the questions coming!
Tuesday, November 9, 2010
Handling popups and browser dialogs in selenium for firefox
Wednesday, November 3, 2010
SIMPLIUM-Simple test framework for Selenium.
Overview
Simplium aids the developer to create selenium based unit test that can be executed in different browsers and environment. With environment means the same test can be run against the developers own machine as well as a test machine somewhere on the network or even the production machine.
A Simplium unit tests doesn't have any reference to which URL the test is executed against as well as no reference to which browser the test should be executed in. Instead the Simplium test cases are annotated with Simplium specific annotations which allow Simplium to take control of the test cases when executed.
Simplium looks for which environment it is executed in (development, test or production) and based on this information Simplium will execute the test cases against different servers, against a local selenium remote control or selenium grid and execute each test in the browsers that the environment has specified.
Download:
Download the latest version of Simplium from http://simplium.sektor.se/download.html
Current version is 0.4.
Quick Example
Take a look at a ordinary Selenium test case.
import junit.framework.TestCase;
import com.thoughtworks.selenium.*;
public class ExampleSeleniumTest extends TestCase {
private Selenium selenium;
public void setUp() {
selenium = new DefaultSelenium("localhost",
4444, "*firefox", "http://www.google.com");
selenium.start(); }
public void testGoogleForSomeThings() throws InterruptedException {
selenium.open("/");
assertEquals("Google", selenium.getTitle());
}
public void tearDown() {
browser.stop();
}
}
This test case has the selenium server host and port specificed in the source code, as well as the browser to run the test case in and also which URL the test should run against.
What if we would like to run this test against our development machine and test machine as well? And what if we also would like to run this test in Internet Explorer, Safari and Chrome? It is here Simplium comes to the rescue.
A Simplium based Selenium test case can look like this
package com.company.test;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.simplium.SimpliumWebTest;
import org.simplium.junit.SimpliumJUnitRunner;
@MyCompanyWebTest
@RunWith(SimpliumJUnitRunner.class)
public class ASimpliumGoogleTest extends SimpliumWebTest {
@Test
public void testGoogleTitle() {
selenium.open("/");
Assert.assertEquals("Google", selenium.getTitle()); }}
The @MyCompanyWebTest is a meta annotation that contains a number of Simplium specific annotation. This annotation combine with a specific JUnit Runner the Simplium can in the backgrund determine the current enviroment, what browser to execute the test case in and to set up a Selenium server.
package com.company.test;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.simplium.annotation.Browsers;
import org.simplium.annotation.Enviroments;
import org.simplium.annotation.Screenshot;
import org.simplium.annotation.Screenshot.CaptureRule;
@Browsers
@Enviroments(
development = {"localhost","4444","http://localhost:8080"},
test = {"grid.company.com","4444","http://test.google.com" },
production = {"grid.company.com","4444","http://www.google.com"}
)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyCompanyWebTest {
}
The @MyCompanyWebTest is listed abow. The @Browsers indicates what browser to use. For now the default browsers are used which means that each test case run in the development enviroment is run in Firefox and Internet Explorer. When using test it is run in a number of other browsers as well.
@Enviroment defines the Selenium server host, port and the URL to test against for each of the three specificed enviroments. This means that for @MyCompanyWebTest a local Selenium server is started in development enviroment and the test is executed against localhost:8080. When running in test Simplium lets a Selenium grid execute the test cases. The grid is located at grid.company.com:4444. The test cases are then executed against test.google.com. Prodution also uses the Selenium grid but the test cases are executed against www.google.com.
To take control of which browser that the test should be executed in and not use the default ones the @Browsers annotation can be feed with this information.
@Browsers(
development = {"*iexplorer","*firefox"},
test = {"*iexplorer","*firefox","*googlechrome","*opera","*safari"},
production = {"*iexplorer","*firefox","*googlechrome","*opera","*safari"}
)
The @Browsers annotation can also be used on a test case method to override the @Browser annotation on the class level. This if some part of the web application can't be executed with certain browser(s).
Simplium also aids the developer to find out why a test case fails. When Simplium javacode that a test case fails, through a assert or by a unknown not caught exception Simplium can be instructed to take a screenshot of the browser so that developer can see exactly what happened on the screen when the fail occured. This is done by marking the meta annotation with the @Screenshot annotation.
@Screenshot(CaptureRule.CAPTURE_WHEN_EXCEPTION_OCCURES)
public @interface MyCompanyWebTest {
}
Simplium will create a .png under the tmp directory followed by the current execution time and the test class that failed.
There is a number of other annotation that also can be used, @Delay, @RunOnlyInDevelopment, @RunOnlyInTest and @RunOnlyInProduction.
How to setup a simple Simplium testcase
Step 1 - Create annotation
First we need to create an annotation that all our Simplium test cases must be annotated with.
package com.company.test;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
@Documented
@Inherited
public @interface MyCompanyWebTest {
}
Note that we annotate this annotation with other annotation making this a so called meta annotation. The @Inherited makes sure that this annotation is inherited for all sub classes to a MyCompanyWebTest annotated super class. @Documented makes this annotation show up in JavaDoc.
Step 2 - Define the enviroments
The newly created annotation must define to Simplium the test enviroments for development, test and production.
package com.company.test;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import org.simplium.annotation.Enviroments;
@Enviroments(
development = {"localhost","4444","http://localhost:8080"},
test = {"grid.selenium.com","4444","http://testenviroment.com" },
production = {"grid.selenium.com","4444","http://www.company.com"}
)
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCompanyWebTest {
}
Each enviroment takes three parameters, the host name of where the selenium server is located, the port the selenium server is listing on and where the selenium test case should be executed against.
In development if there doesn't exist an selenium server on the specified host and port a server is started in the background. For test and production the selenium grid should be used.
The base url where the selenium test case is executed should in the development mode be set to the developers machine, localhost, combined with the port for the local test enviroment. The base url for test and production should point on some test enviroment and the production URL. When running in test or production enviroment these URL can be changed with a system property.
Step 3 - Define the browsers
So we have definied the enviroment but not which browsers that the test cases should be run in.
package com.company.test;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import org.simplium.annotation.Enviroments;
@Enviroments(
development = {"localhost","4444","http://localhost:8080"},
test = {"grid.selenium.com","4444","http://testenviroment.com"},
production = {"grid.selenium.com","4444","http://www.company.com" }
)
@Browsers(
development = { "*iexplore" "*firefox" },
test = {
"*firefox on Windows"
"*firefox on MacOS"
"*firefox on Linux"
"*iexplore on Windows"
"*iexplore on MacOS"
"*safari on MacOS"
"*safari on Windows"
"*opera on Windows"
"*opera on MacOS"
"*opera on Linux"
"*googlechrome on Windows"
},
production = {
"as test"
}
)
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCompanyWebTest {
}
With the use of the @Browser annotation we define that in the development enviroment the test case should be executed in iexplore and firefox. For the test enviroment the same test case is run in a number of browser on different plattforms. Here we use Selenium grid to distribute the execution of the test case to machines running the different plattforms and having the different browsers installed. So the machine that starts the test cases doesn't need to have any browsers installed. For production we simply use the same set as for the test enviroment.
Step 4 - Create your Simplium test case
Now we are ready to start developing the test case.
package com.company.test;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.simplium.SimpliumWebTest;
import org.simplium.junit.SimpliumJUnitRunner;
@MyCompanyWebTest
@RunWith(SimpliumJUnitRunner.class)
public class ASeleniumTest extends SimpliumWebTest {
@Test
public void myTestMethod() {
selenium.open("/mywebapp");
Assert.assertEquals("Example", selenium.getTitle()); }}
The test case must be annotated with the created annotation @MyCompanyWebTest. To run the test case with JUnit the @RunWith annotation should be presented and the SimpliumJunitRunner class must be used. Also the test case must extend the SimpliumWebTest.
Note that the test case doesn't have any information about the executing enviroment such as where the selenium server is located or which browser the test should be executed in.
Step 5 - Run in development mode
When running the test case in any modern IDE (here in Eclipse) Simplium execute the test cases in the different browsers specified by the @Browsers annotation.
Note that the test case is run twice, on for each browser definied in the development enviroment.
Step 6 - Run in test mode
So now the developer has tested the application on his developer machine but what about running the test case again but now against a test machine? Simplium makes this simple. Just add the VM argument -Denviroment=test when running the test cases and Simplium will automaticly use the Selenium grid definied under test and execute the test cases with the browsers that has been defined under test.
Step 7 - Run in production mode
The same applies for running in production mode. Use the VM argument -Denviroment=production to make Simplium execute the test cases with the production settings.
Step 8 - The rest
There is a number of annotation that hasn't been mention so far so to get familiar with these this section explain the usage.
@Screenshot
Simplium also aids the developer to find out why a test case fails. When Simplium javacode that a test case fails, through a assert or by a unknown not caught exception Simplium can be instructed to take a screenshot of the browser so that developer can see exactly what happened on the screen when the fail occured. This is done by marking the meta annotation with the @Screenshot annotation.
@Screenshot(CaptureRule.CAPTURE_WHEN_EXCEPTION_OCCURES)
public @interface MyCompanyWebTest {
}
@Delay
@Delay marks a class or method that all selenium API calls should be delayed. This is usable when debugging a test case. The defaul delay is 1000ms (1s) and this can be changed by setting the delay with the annotation, @Delay(2000) gives 2 second delay.
package com.company.test;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.simplium.SimpliumWebTest;
import org.simplium.junit.SimpliumJUnitRunner;
@MyCompanyWebTest
@RunWith(SimpliumJUnitRunner.class)
public class ASeleniumTest extends SimpliumWebTest {
@Test
@Delay
public void searchOnGoogleForGoogle() {
selenium.open("/");
selenium.type("q", "google");
selenium.click("btnG"); }}
@RunOnlyIn*
There are three annotations @RunOnlyInDevelopment, @RunOnlyInTest and @RunOnlyInProduction that can be used to mark classes or method so that it is only run in the specified enviroment. In below example the test case searchOnGoogleForGoogle will only be run under the developmen enviroment. When run in test or production this test case will be ignored.
package com.company.test;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.simplium.SimpliumWebTest;
import org.simplium.junit.SimpliumJUnitRunner;
@MyCompanyWebTest
@RunWith(SimpliumJUnitRunner.class)
public class ASeleniumTest extends SimpliumWebTest {
@Test
@RunOnlyInTest
public void searchOnGoogleForGoogle() {
selenium.open("/");
selenium.type("q", "google");
selenium.click("btnG");
}
}
@Timeout
Annotation that can be used as a meta annotation, class annotation or method annotation to indicate the timeout time Selenium will use for its "open" and the "waitFor*" actions. It is specified in milliseconds.
package com.company.test;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.simplium.SimpliumWebTest;
import org.simplium.junit.SimpliumJUnitRunner;
@MyCompanyWebTest
@RunWith(SimpliumJUnitRunner.class)
public class ASeleniumTest extends SimpliumWebTest {
@Test
@Timeout(60000)
public void searchOnGoogleForGoogle() {
selenium.open("/");
selenium.type("q", "google");
selenium.click("btnG");
}
}