views:

2847

answers:

5

I am using Selenium with TestNG to test a website. I have created tests using the Selenium IDE and exported them to TestNG with each test being a method in a class. Eg,

For login tests there is a Login class which has methods testLogin(), testLogin2() etc For signup tests there is a Signup class has methods testSignup(), testSignup2(), etc

I am using Ant to run the tests which works fine except that each class will open up a browser and then run its methods, eg, if I have five classes, then five browsers will open simultaneously and then run the tests.

What I want is to get Ant/Selenium/TestNG to just open up one browser and then run all the tests (in the same browser) in all the classes that I have specified in testng.xml. Using the example above, I want one browser to open then run testLogin(), testLogin2(), testSignup(), testSignup2(). If this cannot be achieved, then I want to open a browser, run all tests in a class then close the browser then open another browser then run the set of test methods in the next class.

Any help appreciated. Thanks in advance.

+1  A: 

Today I have found the answer that works for me. Give me a few minutes to gather all code samples :)

Init.java

//base class that will be called before all tests
@Test(groups = "init")
public class Init{

    DefaultSelenium browser;

    public void start(ITestContext itc){
        browser = (DefaultSelenium) itc.getAttribute("browser");
        browser.open("url");
        browser.click("xpath");
    }

}

TemplateForClasses.java

/* - all public methods will be tests
 * - all tests will be called after group init
 * - just before suite will start we will start 1 browser instance
 */
@Test(dependsOnGroup="init")
public class TemplateForClasses{

    DefaultSelenium browser;

    @BeforeSuite
    public void startBrowser(ITestContext itc){
        browser = new DefaultSelenium(host,port,browser_type,url);
        itc.setAttribute("browser",browser);
        browser.start();
    }

    @AfterSuite
    public void stopBrowser(ITestContext itc){
        browser = (DefaultSelenium) itc.getAttribute("browser");
        browser.stop();
    }

    //any other: @Before, @After methods

}

FirstGroupOfTests.java

//all tests classes will inherit preferences set in TemplateForClasses
public class FirstGroupOfTests extends TemplateForClasses{

    public void FirstTest(ITestContext itc){
        browser = (DefaultSelenium) itc.getAttribute("browser");
        //browser.click("start");
    }

}

idea:

  • start browser just once have tests
  • that run before every other tests(isBrowserRunning)
  • refer to browser from single test

This code was tested but currently I took it from the top of my head so possibly I will edit it tomorrow to make it more exact.

Update: This result is based on testng.org documentation + some questions asked by me on stackoverflow + some answers found on several forums/groups

I must add I'm running testng programatically and I'm generating xml on the fly (as it is done on documentation.org). I am using it all in one package, I added package to the xml, included only classes Init + the ones that inherit from TemplateForClasses. If you need that xml, let me know.

Ula Karzelek
A: 

Hi,

I too was stuck in the same problem for quite some time. I'll explain it in the simplest terms possible. Consider the following example:

Class A (contains the code selenium.start();)
|
|(inherited classes)
|--------class B }
|--------class C } Have some @Test methods
|--------class D }

Now everytime we run these test methods it will execute the code in the parent class constructor selenium.start(); Thats when the multiple browsers will all open up on your screen.

Now one by one the test methods will get executed - suppose tests in class B are executed they will be happening in one window, for class C another and so on.

So basically, all you have to do is remove the start() code from the parent constructor and put it somewhere in the classes B, C and D.

As long as you keep working with one selenium object everything will happen in one browser window. When you put start(); that browser will open (if it wasnt open) and a new session is created. stop(); and the session is terminated.

The flow of control goes like this=>
Class A, Class B
Class A, Class C
Class A, Class D

So if you can figure out a way to keep using the same selenium object with only 1 start() and 1 stop() for the entire execution sequence shown above, your test execution will happen in only one browser window.

If you put start() code in class A and stop code in each of B,C and D then you will have 3 windows open and one by one they will close as execution progresses.

If you put start() and stop() code individually in B,C and D then you will see one browser opening, executing test cases, closing. Another will then open, execute test cases for C, close etc.

Hope this helps. :-)

A: 

Hi Ula I have just tried out your code, however I get the following issue with the class TemplateForClasses (extract containing the problem is below).

@BeforeSuite
public void startBrowser(ITestContext itc) {
    browser = new DefaultSelenium();

The constructor 'DefaultSelenium' is undefined.

I'm pretty new to all of this, can you point me in the right direction please?

Mark
Check if you have your libraries correctly added. Currently I'm using selenium-server-standalone-2.0a2.jarAlso: check out my edited answer.
Ula Karzelek
A: 

When I start selenium in the BeforeSuite method and add it to the ITestContext, then start a couple of tests which run in parallel, only the last in the series actually sees this context, the others get their own, that get's seemingly assigned in the BeforeTest method.

Any hints for that?

sml
A: 

I did this with Spring's dependency injection. And the init code is in a factory. I needed a way to have a Selenium instance shared not only between tests but between helper classes. Very seldom is selenium.someMethod() called directly in the tests. It more like helper.goToSomePage() or preferencesPage.changePassword(....).

It could be considered a bad idea to have a Selenium instance shared between tests, but the few bugs it brought were not that hard to find. The tests are run sequentially and the Selenium object need not be thread-safe. The state of the object must be kept consistent though.

For info, Spring is a Java framework and Dependency injection is only a part of it. Other DI frameworks like Guice can of course be used instead.

Pierre Gardin