DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Introducing a Parameterized Test Suite for JUnit 4

Introducing a Parameterized Test Suite for JUnit 4

As JUnit 4 fans will know, you aren't able to parameterize test suites. But now there's an extension, via the Runner class, that will help you out.

Peter Wippermann user avatar by
Peter Wippermann
·
May. 29, 17 · Tutorial
Like (2)
Save
Tweet
Share
18.67K Views

Join the DZone community and get the full member experience.

Join For Free

Parameterization of test cases is a well-known feature of JUnit 4. While some use cases also promote the parameterization of test suites, this feature is not available in the test framework by default. This article introduces an extension for JUnit 4 that provides a new Runner class for this purpose. Applicability in the context of automated GUI tests is shown.

Why Would You Parameterize a Test Suite?

Most of us Java developers are familiar with JUnit and its popular features. We typically define test classes and use test suites to aggregate these tests and give them a hierarchy. Test rules like @BeforeClass or @After are also widely used to set up a test's context. For my part, I knew that tests could also be parameterized and I had seen the Fibonacci example. But I think parameterization is a feature one doesn't have to use often.

Parameterized tests became valuable for me when I started automating GUI tests for web applications with Selenium and WebDriver: Although GUI tests are no unit tests for sure the JUnit framework is very handy for test definition, execution and result aggregation. Integration with CI is also available off the shelf. Once I had reached a good coverage of use cases in a single browser, I wanted to port these test cases to other browsers as well. Thus, I parameterized my tests with the browser being the parameter and ran these tests on Chrome, Firefox and Internet Explorer. Since all my tests should be executed on all browsers, the next logical step was to define these parameters at the test suite once instead of defining them repeatedly for every test class.

Then I stumbled upon a severe limitation of JUnit 4: You can parameterize your tests, but you can't parameterize the test suite that combines all your tests!?

Introducing ParameterizedSuite Runner

In JUnit 4 the execution of a test is done by the Runner and configured by the corresponding annotation  @RunWith. BlockJUnit4ClassRunner is the standard Runnerfor tests and chosen if you don't define any. For defining a test suite you configure @RunWith(Suite.class), similar to a parameterized test: @RunWith(Parameterized.class). So that's mutually exclusive.

But how can you parameterize a test suite if there's no @RunWith(ParameterizedSuite.class)? Well, now you can.

Wanting to define parameters on suite level and having the use case of test automation in mind, I implemented and published an open source library as an extension of JUnit 4. Integration is easy and uses the same patterns as in parameterization of single test classes.

Exemplary Integration

Start by defining another dependency in addition to JUnit 4.
For Maven:

<dependency>
    <!-- https://github.com/PeterWippermann/parameterized-suite -->
    <groupId>com.github.peterwippermann.junit4</groupId>
    <artifactId>parameterized-suite</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>


Make your test suite a ParameterizedSuite and declare a method to produce parameters - just as in a parameterized test class.

import com.github.peterwippermann.junit4.parameterizedsuite.ParameterizedSuite;

@RunWith(ParameterizedSuite.class)
@SuiteClasses({
    OneTest.class,
    TwoTest.class
})
public class MyParameterizedTestSuite {

    @Parameters(name = "Parameters are {0} and {1}")
    public static Object[] params() {
        return new Object[][] {
            {
                'A',
                1
            }, {
                'B',
                2
            }, {
                'C',
                3
            }
        };
    }

    /**
     * Always provide a target for the defined parameters - even if you only want to access them in the suite's child classes.
     * Instead of fields you can also use a constructor with parameters.
     */
    @Parameter(0)
    public char myCharParameter;

    @Parameter(1)
    public int myIntParameter;
}


In JUnit 4 a test suite has no access to the instances of the test classes. This is by the framework’s design. Thus, the parameters have to be transferred via a static context, which is the ParameterContext singleton. Instead of instantiating their own parameters, parameterized test classes refer to the ParameterContext.

@RunWith(Parameterized.class)
public class MyParameterizedTestCase {

    @Parameters(name = "Parameters are {0} and {1}")
    public static Iterable < Object[] > params() {
        if (ParameterContext.isParameterSet()) {
            return Collections.singletonList(ParameterContext.getParameter(Object[].class));
        } else {
            // if the test case is not executed as part of a ParameterizedSuite, you can define fallback parameters
        }
    }

    private char myCharParameter;

    private int myIntParameter;

    public MyParameterizedTestCase(char c, int i) {
        super();
        this.myCharParameter = c;
        this.myIntParameter = i;
    }

    @Test
    public void testWithParameters() {
        // ...
    }
}

Execution Order

The set of test classes in a test suite and the set of parameters the suite defines lead to two alternative execution strategies:

  1. Execute all tests per parameter

  2. Execute each test with all parameters in a row

The current implementation of ParameterizedSuite implements the first strategy, i.e. for each parameter all tests are run before going over to the next parameter. That way instances of parameter objects are handed over from test to test and allow to share state between tests.

Sharing state between tests became especially important in my case for GUI tests: A browser could be set up once and be reused in all tests. That way the session, cookies, current URL and history persisted.

Due to the execution order, only a single parameter instance may be accessed from the ParameterContext at once. During the test suite's execution the test classes will be instantiated multiple times and, consequently, the method annotated with @Parameters will also be called as often.

Enabling Test Rules for Test Suites

 TestRules  encapsulate the execution of a test case and may take additional actions before or after a test is run. Popular examples are @Before, @AfterClass, and @ExternalResource. These test rules are not applicable to default test suites since a test suite is never instantiated. It rather acts as a declaration of the grouped test classes. Opposed to this, a parameterized test suite will also be instantiated and respects any definitions of test rules.

Notes to State-Sharing and Thread-Safety

Parameters of a test suite are only instantiated once and reused in all test classes, which implies these objects are shared state between the test classes! This behavior is actually identical to the parameterisation of single classes using @Parameterized. Nevertheless, state sharing has to be used with care and considered for race conditions. In the context of GUI testing, the sharing of the browser instances is explicitly wanted to preserve the web application’s state.

Regarding race conditions: The current implementation of the ParameterContextis not thread-safe. A concurrent implementation could be based on ThreadLocal. Feature requests or even pull requests are welcome at the project’s site.

Conclusion

The parameterization of test suites is required by few JUnit 4 users, but many of those seem to come from a GUI test automation background. Supporting this feature in the JUnit 4 framework has been discussed but not been carried out. The library parameterized-suite that has been introduced in this article is intended to be an extension of the framework and fills the described feature gap.

unit test Test suite JUnit

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Introduction to Container Orchestration
  • Stop Using Spring Profiles Per Environment
  • Building Microservice in Golang
  • What Are the Benefits of Java Module With Example

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: