Congo-Kinshasa: New Centre Opens At Heart of Record Ebola Outbreak is trending nowVet Debunks Rabies Myths, Urges Vaccination is trending nowNigeria: NAFDAC Joins £3.7m Global Vaccine Safety Project to Combat Fake, Substandard Vac… is trending nowIberia to charter a special plane for the total solar eclipse is trending nowPreviously Unknown Layer of DNA Repair Control Occurs Outside the Nucleus is trending nowVenus rings found high above planet’s thick clouds is trending nowNew genomic approach links rare immune cells to autoimmune disease risk is trending nowJunior D’Tigers, D’Tigress Land In Côte D’Ivoire For 2026 FIBA U18 AfroBasket Challenge is trending nowArokodare Scores on Ajax Debut in Pre-Season Victory is trending nowOsimhen now under pressure to quit Galatasaray is trending nowMr P alleges Jude Okoye threatened him over US property dispute is trending nowFG fine on sponsor forced ‘Who Wants To Be A Millionaire’ off air — Frank Edoho is trending nowCongo-Kinshasa: New Centre Opens At Heart of Record Ebola Outbreak is trending nowVet Debunks Rabies Myths, Urges Vaccination is trending nowNigeria: NAFDAC Joins £3.7m Global Vaccine Safety Project to Combat Fake, Substandard Vac… is trending nowIberia to charter a special plane for the total solar eclipse is trending nowPreviously Unknown Layer of DNA Repair Control Occurs Outside the Nucleus is trending nowVenus rings found high above planet’s thick clouds is trending nowNew genomic approach links rare immune cells to autoimmune disease risk is trending nowJunior D’Tigers, D’Tigress Land In Côte D’Ivoire For 2026 FIBA U18 AfroBasket Challenge is trending nowArokodare Scores on Ajax Debut in Pre-Season Victory is trending nowOsimhen now under pressure to quit Galatasaray is trending nowMr P alleges Jude Okoye threatened him over US property dispute is trending nowFG fine on sponsor forced ‘Who Wants To Be A Millionaire’ off air — Frank Edoho is trending now
Automation Testing
Mastering Parameterized Tests in JUnit with Selenium WebDriver
Automate The Planet - Anton Angelov ··92 views
In the evolving landscape of software testing, efficiency and coverage are paramount. JUnit 5 introduces enhanced parameterized testing capabilities, allowing developers to run the same test with various inputs, significantly reducing redundancy. This article delves into the advanced features...
In the evolving landscape of software testing, efficiency and coverage are paramount. JUnit 5 introduces enhanced parameterized testing capabilities, allowing developers to run the same test with various inputs, significantly reducing redundancy. This article delves into the advanced features of parameterized testing in JUnit 5.
Before exploring parameterized testing, it's crucial to understand the foundations laid by traditional testing methods. The ToDoTests class begins with standard Selenium WebDriver setup, navigating through a web application and validating its behavior with straightforward assertions. This approach, while effective for specific scenarios, can lead to repetitive test cases when dealing with multiple inputs.
What are we going to test? The website is called TodoMVC and is implementing the same TODO app functionality using 30+ most popular web technologies. Everything is open-source and free.
When you click on a particular technology, the corresponding app written on it opens.
We will create a single data-driven test using NUnit, where we will open 20+ technologies. Then we will add a few TODO items, mark as complete the first one and verify the numbers of the items left.
The Selenium Test
The ToDoTests class begins with setting up the Selenium WebDriver environment:
setUpClass(): this method is annotated with @BeforeAll, ensuring that it runs once before all tests in the class. It sets up the ChromeDriver using WebDriverManager, a utility that simplifies the management of driver binaries. setUp(): annotated with @BeforeEach, this method initializes the ChromeDriver, WebDriverWait, and Actions before each test. WebDriverWait is configured with a timeout, and Actions is used for more complex gestures like mouse movements or keyboard inputs.
The core of the ToDoTests class is the verifyToDoListCreatedSuccessfully test:
@TestpublicvoidverifyToDoListCreatedSuccessfully(){// Navigate to the web applicationdriver.navigate().to("https://todomvc.com/");// Open the specific technology appopenTechnologyApp("Backbone.js");// Add new to-do itemsaddNewToDoItem("Clean the car");addNewToDoItem("Clean the house");addNewToDoItem("Buy Ketchup");// Mark an item as completedgetItemCheckbox("Buy Ketchup").click();// Assert the number of items leftassertLeftItems(2);}
The test starts by navigating to the "TodoMVC" web application. It then interacts with the application by selecting a specific technology (Backbone.js in this case) and adding new to-do items. The test marks one item as completed and asserts the expected number of items left using assertLeftItems(2). This assertion ensures that the application's state reflects the user's actions correctly.
The class includes several private helper methods:
privatevoidassertLeftItems(intexpectedCount){varresultSpan=waitAndFindElement(By.xpath("//footer/*/span | //footer/span"));if(expectedCount==1){varexpectedText=String.format("%d item left",expectedCount);validateInnerTextIs(resultSpan,expectedText);}else{varexpectedText=String.format("%d items left",expectedCount);validateInnerTextIs(resultSpan,expectedText);}}privatevoidvalidateInnerTextIs(WebElementresultElement,StringexpectedText){webDriverWait.until(ExpectedConditions.textToBePresentInElement(resultElement,expectedText));}privateWebElementgetItemCheckbox(StringtodoItem){varxpathLocator=String.format("//label[text()='%s']/preceding-sibling::input",todoItem);returnwaitAndFindElement(By.xpath(xpathLocator));}privatevoidopenTechnologyApp(StringtechnologyName){vartechnologyLink=waitAndFindElement(By.linkText(technologyName));technologyLink.click();}privatevoidaddNewToDoItem(StringtodoItem){vartodoInput=waitAndFindElement(By.xpath("//input[@placeholder='What needs to be done?']"));todoInput.sendKeys(todoItem);actions.click(todoInput).sendKeys(Keys.ENTER).perform();}privateWebElementwaitAndFindElement(Bylocator){returnwebDriverWait.until(ExpectedConditions.presenceOfElementLocated(locator));}
assertLeftItems(int expectedCount): asserts the number of items left in the to-do list. validateInnerTextIs(WebElement resultElement, String expectedText): waits until the text of a specific element matches the expected text. getItemCheckbox(String todoItem): finds the checkbox element for a given to-do item. openTechnologyApp(String technologyName): clicks on the link to open a specific technology's to-do list application. addNewToDoItem(String todoItem): adds a new item to the to-do list. waitAndFindElement(By locator): waits until an element is present on the page and returns it.
Finally, the tearDown method annotated with @AfterEach ensures that the browser is closed after each test, preventing resource leaks.
Transitioning to Parameterized Testing
Parameterized tests mark a significant shift from traditional testing, offering a data-driven approach. They allow the execution of the same test logic across a range of inputs, enhancing test coverage and reducing code duplication.
The ToDoTests class can be significantly enhanced by introducing parameterized tests. Consider this upgraded test methods.
Basic Parameterized Tests with Value Sources
We start by replacing repetitive test methods with a single @ParameterizedTest using @ValueSource. This annotation supplies different technology names to test the TodoMVC application, ensuring broad functionality across various frameworks.
@ParameterizedTest(name="{index}. verify todo list created successfully when technology = {0}")@ValueSource(strings={"Backbone.js","AngularJS","React","Vue.js","CanJS","Ember.js","KnockoutJS","Marionette.js","Polymer","Angular 2.0","Dart","Elm","Closure","Vanilla JS","jQuery","cujoJS","Spine","Dojo","Mithril","Kotlin + React","Firebase + AngularJS","Vanilla ES6"})@NullAndEmptySourcepublicvoidverifyToDoListCreatedSuccessfully_withParams(Stringtechnology){driver.navigate().to("https://todomvc.com/");openTechnologyApp(technology);addNewToDoItem("Clean the car");addNewToDoItem("Clean the house");addNewToDoItem("Buy Ketchup");getItemCheckbox("Buy Ketchup").click();assertLeftItems(2);}
The @ValueSource annotation supplies different technology names to the same test logic, verifying the to-do list functionality across various frameworks and libraries. The name = "{index}. verify todo list created successfully when technology = {0} in @ParameterizedTest dynamically names each test iteration, making test results more readable. The inclusion of @NullAndEmptySource ensures that the test logic is also executed with null and empty strings, covering edge cases that might be missed in traditional testing.
Enum Sources for Defined Data Sets
Next, the use of @EnumSource enables testing with enumerated types, providing a clear and manageable approach to handling predefined data sets, like different web technologies.
@ParameterizedTest@EnumSource(WebTechnology.class)publicvoidverifyToDoListCreatedSuccessfully_withEnum(WebTechnologytechnology){driver.navigate().to("https://todomvc.com/");openTechnologyApp(technology.getTechnologyName());addNewToDoItem("Clean the car");addNewToDoItem("Clean the house");addNewToDoItem("Buy Ketchup");getItemCheckbox("Buy Ketchup").click();assertLeftItems(2);}// Enum filter - data driven@ParameterizedTest@EnumSource(value=WebTechnology.class,names={"BACKBONEJS","ANGULARJS","EMBERJS","KNOCKOUTJS"})publicvoidverifyToDoListCreatedSuccessfully_withEnumFilter(WebTechnologytechnology){driver.navigate().to("https://todomvc.com/");openTechnologyApp(technology.getTechnologyName());addNewToDoItem("Clean the car");addNewToDoItem("Clean the house");addNewToDoItem("Buy Ketchup");getItemCheckbox("Buy Ketchup").click();assertLeftItems(2);}// Enum filter exclude - data driven@ParameterizedTest@EnumSource(value=WebTechnology.class,names={"BACKBONEJS","ANGULARJS","EMBERJS","KNOCKOUTJS"},mode=EnumSource.Mode.EXCLUDE)publicvoidverifyToDoListCreatedSuccessfully_withEnumFilterExclude(WebTechnologytechnology){driver.navigate().to("https://todomvc.com/");openTechnologyApp(technology.getTechnologyName());addNewToDoItem("Clean the car");addNewToDoItem("Clean the house");addNewToDoItem("Buy Ketchup");getItemCheckbox("Buy Ketchup").click();assertLeftItems(2);}// Enum filter exclude - data driven@ParameterizedTest@EnumSource(value=WebTechnology.class,names={".+JS"},mode=EnumSource.Mode.EXCLUDE)publicvoidverifyToDoListCreatedSuccessfully_withEnumFilterExcludeRegex(WebTechnologytechnology){driver.navigate().to("https://todomvc.com/");openTechnologyApp(technology.getTechnologyName());addNewToDoItem("Clean the car");addNewToDoItem("Clean the house");addNewToDoItem("Buy Ketchup");getItemCheckbox("Buy Ketchup").click();assertLeftItems(2);}
@EnumSource(WebTechnology.class) automatically provides each constant from the WebTechnology enum as a parameter to the test method. This approach is ideal for cases where the set of inputs is known and finite, like different technology stacks. Enum constants can be filtered based on a regular expression, providing a dynamic way to select test parameters.
Utilizing CSV Sources
Building upon the foundation of parameterized testing, the ToDoTests class introduces another powerful feature: @CsvSource. This annotation enables the use of comma-separated values (CSV) to provide parameters for the test, offering an easy way to include complex test data.
// CSV Source without file@ParameterizedTest@CsvSource(value={"Backbone.js,Clean the car,Clean the house,Buy Ketchup,Buy Ketchup,2","AngularJS,Clean the car,Clean the house,Clean the house,Clean the house,2","React,Clean the car,Clean the house,Clean the car,Clean the car,2"},delimiter=',')publicvoidverifyToDoListCreatedSuccessfully_withParamsCsvSourceWithoutFile(Stringtechnology,Stringitem1,Stringitem2,Stringitem3,StringitemToCheck,intexpectedLeftItems){driver.navigate().to("https://todomvc.com/");openTechnologyApp(technology);addNewToDoItem(item1);addNewToDoItem(item2);addNewToDoItem(item3);getItemCheckbox(itemToCheck).click();assertLeftItems(expectedLeftItems);}
@CsvSource allows specifying a list of values for each parameter of the test method. Each line represents a different test scenario. This approach tests the application with various technologies and task combinations, ensuring broad functionality coverage. The delimiter attribute is set to ',', which is standard for CSV data.
CSV File Source
In addition to inline CSV sources, JUnit 5's parameterized tests can also leverage external CSV files for data-driven testing. This approach is exemplified in the ToDoTests class, offering a structured and scalable way to manage test data.
@CsvFileSource reads test data from an external CSV file, allowing for a clean separation of test logic and test data. This method is particularly useful when dealing with large datasets or when the data needs to be shared across multiple tests. The numLinesToSkip attribute is set to 1, useful for skipping header lines in the CSV file.
Advanced Parameterized Testing with @MethodSource
Building on the concepts of parameterized testing, JUnit 5's @MethodSource offers a flexible and powerful way to supply complex parameters to tests. This is particularly useful when test parameters are not just simple values but need some computation or custom logic for generation.
@ParameterizedTest@MethodSource("provideWebTechnologies")publicvoidverifyToDoListCreatedSuccessfully_withMethod(Stringtechnology){driver.navigate().to("https://todomvc.com/");openTechnologyApp(technology);addNewToDoItem("Clean the car");addNewToDoItem("Clean the house");addNewToDoItem("Buy Ketchup");getItemCheckbox("Buy Ketchup").click();assertLeftItems(2);}privatestaticStream<String>provideWebTechnologies(){returnStream.of("Backbone.js","AngularJS","React","Vue.js","CanJS","Ember.js","KnockoutJS","Marionette.js","Polymer","Angular 2.0","Dart","Elm","Closure","Vanilla JS","jQuery","cujoJS","Spine","Dojo","Mithril","Kotlin + React","Firebase + AngularJS","Vanilla ES6");}
@MethodSource("provideWebTechnologies") indicates that the parameters for the test will be supplied by the provideWebTechnologies method. The method provideWebTechnologies returns a stream of strings, each representing a different web technology, demonstrating how complex logic can be used to generate test parameters. This approach allows for dynamic generation of test data, which can include complex computations or conditional logic. The method providing the parameters can be reused across different tests, promoting code reuse and maintainability. As the complexity of test data grows, @MethodSource keeps tests clean and focused, with the data generation logic neatly separated.
Mastering Complex Parameterized Tests with @MethodSource and Multiple Parameters
The ToDoTests class showcases an advanced use of @MethodSource in JUnit 5, handling multiple parameters for comprehensive and dynamic testing scenarios.