Thomas Sundberg

July 11, 2010

Parameterized JUnits tests

We want to run the same test more than once and only vary the parameters. The solution is to use JUnit and run our
tests with the Parameterized JUnit runner.

The example is built with Maven. Maven is a great tool that allows you to build Java code while not considering
which IDE the system is written with.

Let’s start with the file layout:


    src ---+-- main -- java -- se.sigma.junit.Mirror.java
           |
           |
           +-- test -- java -- se.sigma.junit.GoogleTest.java
                                              MirrorTest.java
                                              ParameterizedGoogleTest.java
                                              ParameterizedMirrorTest.java
    pom.xml

The Maven pom.xml looks like this:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>se.sigma.junit</groupId>
    <artifactId>parameterized-junit-test</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
    <name>Parameterized JUnit Test Example</name>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-server</artifactId>
            <version>2.0a4</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

We have two dependencies. JUnit is needed to be able to run the tests. We need selenium-server so we can use
Selenium/WebDriver to test a web site.

Let’s start with the first test. A simple test that will verify that whatever we send into a mirror is returned.

package se.sigma.junit;

import org.junit.Test;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class MirrorTest {
    private String expected = "My reflection";

    @Test
    public void testReflection() {
        Mirror mirror = new Mirror();
        String actual = mirror.reflect(expected);

        assertThat(actual, is(expected));
    }
}

The production code that will satisfy the test follows. It is a real simple class, we only return whatever is sent
to us:

package se.sigma.junit;

public class Mirror {
    public String reflect(String reflection) {
        return reflection;
    }
}

We could copy the test and change the value we use for testing if we wanted to test with another test data. This
would perhaps not be the greatest solution. Another approach could be to reuse the test and just vary the test data.
We could create a parameterized JUnit test to do this.

package se.sigma.junit;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

@RunWith(Parameterized.class)
public class ParameterizedMirrorTest {
    private String expected;

    public ParameterizedMirrorTest(String expected) {
        this.expected = expected;
    }

    @Test
    public void testReflection() {
        Mirror mirror = new Mirror();
        String actual = mirror.reflect(expected);

        assertThat(actual, is(expected));
    }

    @Parameterized.Parameters
    public static Collection<String[]> testData() {
        List<String[]> expectedTestData = new LinkedList<String[]>();

        expectedTestData.add(new String[]{"My reflection"});
        expectedTestData.add(new String[]{"Your reflection"});

        return expectedTestData;
    }
}

Start with defining to run the test with a parameterized test runner, ‘@RunWith(Parameterized.class)’.

Then annotate a method with ‘@Parameterized.Parameters’ that will return a Collection of arrays with the parameters
that will be used to construct the test class.

That’s it. If we add one more array to the List ‘expectedTestData’, one more example will be executed.

We could do the same thing if we wanted to test a web site with more than one browser.

Let’s start with a simple case, let’s test Google with Firefox.

package se.sigma.junit;

import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;

import static junit.framework.Assert.assertTrue;

public class GoogleTest {
    private WebDriver driver = new FirefoxDriver();

    @Test
    public void googleSearch() {
        driver.get("http://www.google.com");
        
        WebElement searchArea = driver.findElement(By.name("q"));
        searchArea.sendKeys("JUnit");

        WebElement searchButton = driver.findElement(By.name("btnG"));
        searchButton.click();

        String pageSource = driver.getPageSource();
        assertTrue(pageSource.contains("JUnit"));
        
        driver.close();
    }
}

It’s trivial to extend this example so we test Google with two browsers:

package se.sigma.junit;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import static junit.framework.Assert.assertTrue;

@RunWith(Parameterized.class)
public class ParameterizedGoogleTest {
    private WebDriver driver;

    public ParameterizedGoogleTest(WebDriver driver) {
        this.driver = driver;
    }

    @Test
    public void googleSearch() {
        driver.get("http://www.google.com");

        WebElement searchArea = driver.findElement(By.name("q"));
        searchArea.sendKeys("JUnit");

        WebElement searchButton = driver.findElement(By.name("btnG"));
        searchButton.click();

        String pageSource = driver.getPageSource();
        assertTrue(pageSource.contains("JUnit"));

        driver.close();
    }

    @Parameterized.Parameters
    public static Collection<WebDriver[]> drivers() {
        List<WebDriver[]> drivers = new LinkedList<WebDriver[]>();
        drivers.add(new WebDriver[]{new FirefoxDriver()});
        drivers.add(new WebDriver[]{new InternetExplorerDriver()});

        return drivers;
    }
}

The google test has been extended so it will be executed with a parameterized test runner and a method that will
return instances of WebDrivers that will be used to browse Google. The WebDrivers are beeing returned in a
collection of arrays that will be used to construct the test class.

The result is that we will be able to test searching at Google with both Firefox and Internet Explorer.

Resources

  • JUnit – A testing framework for unit testing Java code
  • Selenium/WebDriver – A testing framework for testing web sites through a browser
  • Maven – A build system for building Java code
  • Thomas Sundberg – The author
About these ads

5 Comments »

  1. [...] This post was mentioned on Twitter by Alexandru Bolboaca. Alexandru Bolboaca said: RT @thomassundberg: New blog post: http://ht.ly/29SDe Parameterized JUnit [...]

    Pingback by Tweets that mention Parameterized JUnits tests « Thomas Sundberg -- Topsy.com — July 12, 2010 @ 09:49

  2. The parameterized JUnit test test works as expected if there is one @Test because driver.close() will tidy up nicely. However, when there are 2 or more it becomes more problematic (we can’t call driver.close() within the tests if we want to run more than one @Test).

    I’ve tried using driver.quit() in an @AfterClass annotation but that leaves all but the last browser session windows.

    I’ll post my code below and reply back when/if i find a solution. Thanks!


    package com.clickfox.selenium.wd.util;

    import static junit.framework.Assert.assertTrue;

    import java.util.Collection;
    import java.util.LinkedList;
    import java.util.List;

    import org.junit.AfterClass;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.openqa.selenium.ie.InternetExplorerDriver;

    @RunWith(Parameterized.class)
    public class ParameterizedClassExample
    {
    private static WebDriver driver;

    public ParameterizedClassExample(WebDriver driver)
    {
    this.driver = driver;
    }

    @Parameterized.Parameters
    public static Collection drivers()
    {
    List drivers = new LinkedList();
    drivers.add(new WebDriver[] { new ChromeDriver() });
    drivers.add(new WebDriver[] { new InternetExplorerDriver() });
    drivers.add(new WebDriver[] { new FirefoxDriver() });

    return drivers;
    }

    // @After
    // public void cleanup()
    // throws Exception
    // {
    // driver.quit();
    // }

    @AfterClass
    public static void teardown()
    {
    System.out.print("This is the AfterClass.");
    driver.quit();
    }

    @Test
    public void googleSearch()
    {
    driver.get("http://www.google.com");

    WebElement searchArea = driver.findElement(By.name("q"));
    searchArea.sendKeys("JUnit");

    WebElement searchButton = driver.findElement(By.name("btnG"));
    searchButton.click();

    String pageSource = driver.getPageSource();
    assertTrue(pageSource.contains("JUnit"));

    // driver.close();

    }

    @Test
    public void googleSearch2()
    {
    driver.get("http://www.google.com");

    WebElement searchArea = driver.findElement(By.name("q"));
    searchArea.sendKeys("JUnit");

    WebElement searchButton = driver.findElement(By.name("btnG"));
    searchButton.click();

    String pageSource = driver.getPageSource();
    assertTrue(pageSource.contains("JUnit"));

    // driver.quit();

    }

    }

    Comment by rhy — September 7, 2012 @ 22:49

    • Hi!

      What about storing all driver instances in a static list and close them in the after class method? I just verified that this code doesnt leave any browser windows running.

      package com.clickfox.selenium.wd.util;

      import org.junit.AfterClass;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.junit.runners.Parameterized;
      import org.openqa.selenium.By;
      import org.openqa.selenium.WebDriver;
      import org.openqa.selenium.WebElement;
      import org.openqa.selenium.firefox.FirefoxDriver;

      import java.util.Collection;
      import java.util.LinkedList;
      import java.util.List;

      import static junit.framework.Assert.assertTrue;

      @RunWith(Parameterized.class)
      public class ParameterizedClassExample {
      private static List allDrivers = new LinkedList();
      private WebDriver driver;

      public ParameterizedClassExample(WebDriver driver) {
      this.driver = driver;
      allDrivers.add(driver);
      }

      @Parameterized.Parameters
      public static Collection drivers() {
      List drivers = new LinkedList();
      drivers.add(new WebDriver[]{new FirefoxDriver()});
      drivers.add(new WebDriver[]{new FirefoxDriver()});

      return drivers;
      }

      @AfterClass
      public static void teardown() {
      System.out.print(“This is the AfterClass.”);

      for (WebDriver webDriver : allDrivers) {
      webDriver.quit();
      }
      }

      @Test
      public void googleSearch() {
      driver.get(“http://www.google.com”);

      WebElement searchArea = driver.findElement(By.name(“q”));
      searchArea.sendKeys(“JUnit”);

      WebElement searchButton = driver.findElement(By.name(“btnG”));
      searchButton.click();

      String pageSource = driver.getPageSource();
      assertTrue(pageSource.contains(“JUnit”));
      }

      @Test
      public void googleSearch2() {
      driver.get(“http://www.google.com”);

      WebElement searchArea = driver.findElement(By.name(“q”));
      searchArea.sendKeys(“TestNG”);

      WebElement searchButton = driver.findElement(By.name(“btnG”));
      searchButton.click();

      String pageSource = driver.getPageSource();
      assertTrue(pageSource.contains(“TestNG”));
      }
      }

      HTH
      Thomas

      Comment by Thomas Sundberg — September 8, 2012 @ 10:08

  3. Actually there have been some improvements concerning parameterized tests in JUnit. Please have a glance at JUnit Params from Pragmatists (http://code.google.com/p/junitparams). The general idea is more or less the same, but the lib makes it easier and more convenient to define the params.

    Comment by Paweł Rychlik — October 26, 2012 @ 10:49

    • Interesting, I don’t think I have heard of JUnit Params before.

      /Thomas

      Comment by Thomas Sundberg — October 26, 2012 @ 12:52


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Theme: Customized Silver is the New Black. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 39 other followers

%d bloggers like this: