Parameterized JUnits tests

Filed under: JUnit, Java, Selenium, — Tags: Integration test — Thomas Sundberg — 2010-07-11

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



(less...)

Pages

About
Events
Why

Categories

Agile
Automation
BDD
Clean code
Continuous delivery
Continuous deployment
Continuous integration
Cucumber
Culture
Design
DevOps
Executable specification
Git
Gradle
Guice
J2EE
JUnit
Java
Javascript
Kubernetes
Linux
Load testing
Maven
Mockito
New developers
Pair programming
PicoContainer
Presentation
Programming
Public speaking
Quality
React
Recruiting
Requirements
Scala
Selenium
Software craftsmanship
Software development
Spring
TDD
Teaching
Technical debt
Test automation
Tools
Web
Windows
eXtreme Programming

Authors

Thomas Sundberg
Adrian Bolboaca

Archives

Meta

rss RSS