CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-junit-jupiter--junit-jupiter-params

JUnit Jupiter extension for parameterized tests

Pending
Overview
Eval results
Files

csv-sources.mddocs/

CSV Data Sources

Comprehensive CSV data support for inline data and external files with extensive parsing customization options.

Capabilities

@CsvSource Annotation

Provides CSV data inline as test arguments with extensive parsing customization.

/**
 * Provides CSV data inline as arguments to parameterized tests
 */
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
@ArgumentsSource(CsvArgumentsProvider.class)
@Repeatable(CsvSources.class)
@interface CsvSource {
    /**
     * Array of CSV records
     */
    String[] value() default {};
    
    /**
     * CSV data as text block (Java 15+ syntax)
     */
    String textBlock() default "";
    
    /**
     * Use first row as headers in display names
     */
    boolean useHeadersInDisplayName() default false;
    
    /**
     * Quote character for escaping
     */
    char quoteCharacter() default '\'';
    
    /**
     * Single character delimiter
     */
    char delimiter() default ',';
    
    /**
     * Multi-character delimiter string (takes precedence over delimiter)
     */
    String delimiterString() default "";
    
    /**
     * Value to use for empty quoted strings
     */
    String emptyValue() default "";
    
    /**
     * Custom strings that represent null values
     */
    String[] nullValues() default "";
    
    /**
     * Maximum characters per column (protection against malformed data)
     */
    int maxCharsPerColumn() default 4096;
    
    /**
     * Whether to trim whitespace from unquoted values
     */
    boolean ignoreLeadingAndTrailingWhitespace() default true;
}

Usage Examples:

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

class CsvSourceExamples {

    // Basic CSV data
    @ParameterizedTest
    @CsvSource({
        "1, apple, true",
        "2, banana, false",
        "3, cherry, true"
    })
    void testBasicCsv(int id, String name, boolean active) {
        assertTrue(id > 0);
        assertNotNull(name);
    }

    // Custom delimiter
    @ParameterizedTest
    @CsvSource(value = {
        "1|apple|red",
        "2|banana|yellow", 
        "3|cherry|red"
    }, delimiter = '|')
    void testCustomDelimiter(int id, String fruit, String color) {
        assertTrue(id > 0);
        assertNotNull(fruit);
        assertNotNull(color);
    }

    // Multi-character delimiter
    @ParameterizedTest
    @CsvSource(value = {
        "apple::red::sweet",
        "lemon::yellow::sour"
    }, delimiterString = "::")
    void testMultiCharDelimiter(String fruit, String color, String taste) {
        assertNotNull(fruit);
        assertNotNull(color);
        assertNotNull(taste);
    }

    // Quoted values with commas
    @ParameterizedTest
    @CsvSource({
        "'John Doe', 'San Francisco, CA', 94102",
        "'Jane Smith', 'New York, NY', 10001"
    })
    void testQuotedValues(String name, String city, int zipCode) {
        assertTrue(name.contains(" "));
        assertTrue(city.contains(","));
        assertTrue(zipCode > 0);
    }

    // Null and empty value handling
    @ParameterizedTest
    @CsvSource(value = {
        "apple, , sweet",      // Empty middle value
        "banana, yellow, ",    // Empty last value
        "cherry, red, NIL"     // Custom null value
    }, nullValues = {"NIL"}, emptyValue = "EMPTY")
    void testNullAndEmptyValues(String fruit, String color, String taste) {
        assertNotNull(fruit);
        // color and taste may be null or "EMPTY"
    }

    // Headers in display names  
    @ParameterizedTest(name = "Product: {arguments}")
    @CsvSource(value = {
        "ID, Name, Price",
        "1, Apple, 1.50",
        "2, Banana, 0.75"
    }, useHeadersInDisplayName = true)
    void testWithHeaders(String id, String name, String price) {
        assertNotNull(id);
        assertNotNull(name);
        assertNotNull(price);
    }

    // Text block syntax (Java 15+)
    @ParameterizedTest
    @CsvSource(textBlock = """
        1, apple,  1.50
        2, banana, 0.75
        3, cherry, 2.00
        """)
    void testTextBlock(int id, String fruit, double price) {
        assertTrue(id > 0);
        assertNotNull(fruit);
        assertTrue(price > 0);
    }

    // Whitespace handling
    @ParameterizedTest
    @CsvSource(value = {
        " apple , red ",        // Whitespace will be trimmed
        "'  banana  ', yellow"  // Quoted whitespace preserved  
    }, ignoreLeadingAndTrailingWhitespace = true)
    void testWhitespaceHandling(String fruit, String color) {
        // apple will be trimmed, "  banana  " will preserve spaces
        assertNotNull(fruit);
        assertNotNull(color);
    }
}

@CsvFileSource Annotation

Loads CSV data from classpath resources or file system files.

/**
 * Loads CSV data from external files as arguments to parameterized tests
 */
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
@ArgumentsSource(CsvFileArgumentsProvider.class)
@Repeatable(CsvFileSources.class)
@interface CsvFileSource {
    /**
     * Classpath resources to load CSV data from
     */
    String[] resources() default {};
    
    /**
     * File system paths to load CSV data from
     */
    String[] files() default {};
    
    /**
     * Character encoding for file reading
     */
    String encoding() default "UTF-8";
    
    /**
     * Line separator for parsing
     */
    String lineSeparator() default "\n";
    
    /**
     * Number of lines to skip from beginning (e.g., headers)
     */
    int numLinesToSkip() default 0;
    
    // Inherits all parsing attributes from @CsvSource
    boolean useHeadersInDisplayName() default false;
    char quoteCharacter() default '"';
    char delimiter() default ',';
    String delimiterString() default "";
    String emptyValue() default "";
    String[] nullValues() default "";
    int maxCharsPerColumn() default 4096;
    boolean ignoreLeadingAndTrailingWhitespace() default true;
}

Usage Examples:

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;

class CsvFileSourceExamples {

    // Load from classpath resource
    @ParameterizedTest
    @CsvFileSource(resources = "/test-data/products.csv")
    void testFromClasspathResource(int id, String name, double price) {
        assertTrue(id > 0);
        assertNotNull(name);
        assertTrue(price >= 0);
    }

    // Load from file system
    @ParameterizedTest
    @CsvFileSource(files = "src/test/resources/users.csv")
    void testFromFile(String username, String email, int age) {
        assertNotNull(username);
        assertTrue(email.contains("@"));
        assertTrue(age >= 0);
    }

    // Skip header rows
    @ParameterizedTest
    @CsvFileSource(
        resources = "/test-data/products-with-headers.csv",
        numLinesToSkip = 1
    )
    void testSkipHeaders(int id, String name, double price) {
        assertTrue(id > 0);
        assertNotNull(name);
        assertTrue(price >= 0);
    }

    // Custom encoding and delimiter
    @ParameterizedTest
    @CsvFileSource(
        resources = "/test-data/international.csv",
        encoding = "UTF-8",
        delimiter = ';'
    )
    void testCustomEncodingAndDelimiter(String name, String country, String currency) {
        assertNotNull(name);
        assertNotNull(country);
        assertNotNull(currency);
    }

    // Multiple files
    @ParameterizedTest
    @CsvFileSource(resources = {
        "/test-data/products-q1.csv",
        "/test-data/products-q2.csv"
    })
    void testMultipleFiles(int id, String name, double price) {
        assertTrue(id > 0);
        assertNotNull(name);
        assertTrue(price >= 0);
    }

    // With custom null values
    @ParameterizedTest
    @CsvFileSource(
        resources = "/test-data/incomplete-data.csv",
        nullValues = {"N/A", "NULL", ""}
    )
    void testWithNullValues(String name, String value, String category) {
        assertNotNull(name); // name should never be null
        // value and category may be null based on nullValues
    }
}

CSV Parsing Exception

Exception thrown when CSV parsing fails due to malformed data or configuration issues.

/**
 * Exception thrown when CSV parsing fails
 */
@API(status = STABLE, since = "5.0")
class CsvParsingException extends JUnitException {
    /**
     * Constructs exception with message
     */
    CsvParsingException(String message) { }
    
    /**
     * Constructs exception with message and cause
     */
    CsvParsingException(String message, Throwable cause) { }
}

Container Annotations

Container annotations for multiple CSV source annotations.

/**
 * Container annotation for multiple @CsvSource annotations
 */
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
@interface CsvSources {
    CsvSource[] value();
}

/**
 * Container annotation for multiple @CsvFileSource annotations
 */
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@API(status = STABLE, since = "5.0")
@interface CsvFileSources {
    CsvFileSource[] value();
}

Advanced CSV Features:

class AdvancedCsvExamples {

    // Complex CSV with various data types
    @ParameterizedTest
    @CsvSource({
        "1, 'Product A', 19.99, true, 2023-01-15",
        "2, 'Product B', 29.50, false, 2023-02-20",
        "3, 'Product \"Special\"', 39.99, true, 2023-03-10"
    })
    void testComplexCsv(int id, String name, double price, boolean available, String date) {
        assertTrue(id > 0);
        assertNotNull(name);
        assertTrue(price > 0);
        assertNotNull(date);
    }

    // Handling special characters and escaping
    @ParameterizedTest
    @CsvSource(value = {
        "apple|'red, juicy'|1.50",
        "banana|yellow|0.75",
        "cherry|'dark red'|2.00"
    }, delimiter = '|')
    void testSpecialCharacters(String fruit, String description, double price) {
        assertNotNull(fruit);
        assertNotNull(description);
        assertTrue(price > 0);
    }
}

The CSV sources provide powerful data-driven testing capabilities with fine-grained control over parsing behavior, making them ideal for complex test scenarios with structured data.

Install with Tessl CLI

npx tessl i tessl/maven-org-junit-jupiter--junit-jupiter-params

docs

argument-aggregation.md

argument-conversion.md

core-testing.md

csv-sources.md

custom-sources.md

enum-method-sources.md

index.md

value-sources.md

tile.json