idunno
idunno

Reputation: 713

Is there a equivalent of testNG's @BeforeSuite in JUnit 4?

I'm new to the test automation scene so forgive me if this is a stupid question but google has failed me this time. Or at least anything I've read has just confused me further.

I'm using JUnit 4 and Selenium Webdriver within Eclipse. I have several tests that I need to run as a suite and also individually. At the moment these tests run fine when run on their own. At the start of the test an input box is presented to the tester/user asking first what server they wish to test on (this is a string variable which becomes part of a URL) and what browser they wish to test against. At the moment when running the tests in a suite the user is asked this at the beginning of each test, because obviously this is coded into each of their @Before methods.

How do I take in these values once, and pass them to each of the test methods?

So if server = "server1" and browser = "firefox" then firefox is the browser I want selenium to use and the URL I want it to open is http://server1.blah.com/ for all of the following test methods. The reason I've been using seperate @Before methods is because the required URL is slightly different for each test method. i.e each method tests a different page, such as server1.blah.com/something and server1.blah.com/somethingElse

The tests run fine, I just don't want to keep inputting the values because the number of test methods will eventually be quiet large.

I could also convert my tests to testNG if there is an easier way of doing this in testNG. I thought the @BeforeSuite annotation might work but now I'm not sure.

Any suggestions and criticism (the constructive kind) are much appreciated

Upvotes: 8

Views: 7913

Answers (4)

Ben
Ben

Reputation: 4965

If using @RunWith(Suite.class), you can add static methods with @BeforeClass (and @AfterClass), which will run before (and after) the entire Suite you define. See this question.

This of course won't help if you are referring to the entire set of classes found dynamically, and are not using Suite runner.

Upvotes: 0

Cedric Beust
Cedric Beust

Reputation: 15608

I think the main functionality of TestNG that will be useful here is not just @BeforeSuite but @DataProviders, which make it trivial to run the same test with a different set of values (and won't require you to use statics, which always become a liability down the road).

You might also be interested in TestNG's scripting support, which makes it trivial to ask the user for some input before the tests start, here is an example of what you can do with BeanShell.

Upvotes: 1

Matthew Farwell
Matthew Farwell

Reputation: 61705

You can adapt the solution for setting a global variable for a suite in this answer to JUnit 4 Test invocation.

Basically, you extend Suite to create MySuite. This creates a static variable/method which is accessible from your tests. Then, in your tests, you check the value of this variable. If it's set, you use the value. If not, then you get it. This allows you to run a single test and a suite of tests, but you'll only ask the user once.

So, your suite will look like:

public class MySuite extends Suite {
    public static String url;

    /**
     * Called reflectively on classes annotated with <code>@RunWith(Suite.class)</code>
     * 
     * @param klass the root class
     * @param builder builds runners for classes in the suite
     * @throws InitializationError
     */
    public MySuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
        this(builder, klass, getAnnotatedClasses(klass));
        // put your global setup here
        MySuite.url = getUrlFromUser();
    }
}

This would be used in your Suite like so:

@RunWith(MySuite.class)
@SuiteClasses({FooTest.class, BarTest.class, BazTest.class});

Then, in your test classes, you can either do something in the @Before/@After, or better look at TestRule, or if you want Before and After behaviour, look at ExternalResource. ExternalResource looks like this:

public static class FooTest {
    private String url;

    @Rule
    public ExternalResource resource= new ExternalResource() {
        @Override
        protected void before() throws Throwable {
            url = (MySuite.url != null) ? MySuite.url : getUrlFromUser();
        };

        @Override
        protected void after() {
            // if necessary
        };
    };

    @Test
    public void testFoo() {
        // something which uses resource.url
    }
}

You can of course externalize the ExternalResource class, and use it from multiple Test Cases.

Upvotes: 1

Sam
Sam

Reputation: 2437

It might make sense to group tests so that the test suite will have the same @Before method code, so you have a test suite for each separate.

Another option might be to use the same base url for each test but navigate to the specific page by getting selenium to click through to where you want to carry out the test.

Upvotes: 0

Related Questions