In a JUnit 5 @CsvSource row, what value does the test method receive for a column that is left empty, and how do you deliberately pass an empty String or a null using the nullValues and emptyValue attributes?
answer
- Unquoted empty → null, always
- Quoted '' → emptyValue (default empty String)
- emptyValue does not affect unquoted blanks
- nullValues = {"NIL","N/A"} → extra null tokens
- null cannot bind to int — use Integer
basics
~20 sAn unquoted empty column becomes null. A quoted empty column ('') becomes the emptyValue, which defaults to the empty String. Use emptyValue to substitute something else, and nullValues to list tokens such as NIL or N/A that should also convert to null.
solid answer
~40 sTwo rules cover it: - **Unquoted empty → `null`.** `"a, , c"` passes `null` for the middle parameter, always — `emptyValue` does not change this. - **Quoted empty → `emptyValue`.** `"a, '', c"` passes whatever `emptyValue` is set to, and its default is the empty String `""`. So the distinction between "nothing" and "an empty string" is expressed by the quotes, which is the part candidates get wrong. `nullValues` adds custom null tokens: `@CsvSource(nullValues = {"NIL", "N/A"}, ...)` makes those cells arrive as `null` — handy when the CSV is human-authored or exported from a spreadsheet. A practical consequence: `null` can only bind to a reference parameter. `@CsvSource({"1, "})` against `(int a, int b)` fails, because `null` cannot be unboxed to `int`; declare `Integer` when a column may be absent.
code
java · 11 lines@ParameterizedTest
@CsvSource(nullValues = "NIL", textBlock = """
NIL, false
, false
'', false
' ', false
alice, true
""")
void rejectsBlankNames(String name, boolean valid) {
assertEquals(valid, UserValidator.isValidName(name));
}go deeper
Memorise the pair: blank means null, '' means empty string. That alone answers most screening versions of this question.
Add emptyValue and nullValues, and note that emptyValue never rescues an unquoted blank.
Bring the primitive-unboxing failure and the design habit of covering null, empty and whitespace-only in one table when testing validators.
Frame it as fixture legibility — explicit NIL tokens beat invisible blank cells in files other people edit, and the parameter type is a contract across every row.
## Why this exists CSV has no type system and no concept of "absent". A cell is either some characters or no characters, so any CSV-based test source has to invent a convention for `null` versus empty string. JUnit 5 picked one and stuck to it, and the convention is the single most-missed detail of `@CsvSource`. ## The two rules **Rule 1 — an unquoted empty value is converted to `null`, unconditionally.** ```java @CsvSource({"apple, , 1"}) // second parameter receives null ``` This holds *regardless* of the `emptyValue` attribute. The documentation is explicit about it, and it is the behaviour that trips people up when they set `emptyValue` expecting it to catch blank cells. **Rule 2 — a quoted empty value is converted to `emptyValue`, which defaults to the empty String.** ```java @CsvSource({"apple, '', 1"}) // second parameter receives "" ``` Remember `@CsvSource`'s quote character is the single quote `'`, so `''` is the quoted-empty spelling. (`@CsvFileSource` uses `"` by default, so there the spelling is `""`.) Together: **the quotes are the type declaration.** Nothing at all means absent; an explicit empty pair means present-but-empty. That is precisely the distinction you usually want to test against a validator or a parser. ## emptyValue `emptyValue` changes what a *quoted empty* cell becomes: ```java @ParameterizedTest @CsvSource(emptyValue = "EMPTY", textBlock = """ apple, '', 1 banana, , 2 """) void check(String fruit, String note, int rank) { } ``` Row one gives `note = "EMPTY"`. Row two still gives `note = null`. Use it when the empty string is awkward to read in a fixture, or when the parameter type needs a sentinel rather than a blank. ## nullValues `nullValues` lists textual tokens that should be converted to `null` in addition to the unquoted-empty case: ```java @CsvSource(nullValues = {"NIL", "N/A"}, textBlock = """ apple, 1 NIL, 0 N/A, -1 """) ``` Rows two and three pass `null` for the first parameter. This matters most with `@CsvFileSource`, where the file is often exported from a spreadsheet or written by a non-developer who typed `N/A`, and with tables where a literal blank cell would be invisible in review. An explicit `NIL` token is self-documenting in a way an empty gap between two commas is not. One subtlety: matching happens on the *trimmed, unquoted* token. If a cell is quoted — `'NIL'` — it is a literal string, not a null. That gives you a way to test the string `"NIL"` in the same table that uses `NIL` as a null marker. ## Nulls and primitive parameters `null` cannot be converted to a primitive. This fails: ```java @ParameterizedTest @CsvSource({"1, "}) void bad(int a, int b) { } // cannot unbox null into int ``` The failure message is about argument conversion, and the fix is to declare the nullable column as a wrapper type — `Integer b` — or as `String` if the test is about parsing. Any column that may be blank in *any* row must have a reference-typed parameter, because the parameter type is fixed for the whole table. The same applies to enum and `java.time` parameters — those are reference types, so `null` binds fine. ## Practical patterns - **Validation tables.** A single `@CsvSource` covering `null`, `''`, whitespace-only and a valid value is a compact, complete test of an input validator — and the three degenerate cases are spelled `,`, `''` and `' '` respectively (the last needs quoting, otherwise trimming would erase it into `null`). - **Optional fields.** Model an absent field as an unquoted blank and declare the parameter as a wrapper or `String`. - **Human-maintained files.** Set `nullValues = {"", "N/A", "NULL"}` so a spreadsheet export behaves predictably no matter how the author expressed "nothing". ## What to say in an interview State the two rules crisply, note that `emptyValue` does *not* rescue an unquoted blank, mention `nullValues` for custom tokens, and finish with the primitive-parameter consequence. That sequence covers the mechanism and the failure mode people actually hit.
- If you set emptyValue = "EMPTY", what does an unquoted blank column produce?Still `null`. `emptyValue` only applies to a *quoted* empty value such as `''`; an unquoted empty cell is converted to a null reference regardless of the attribute. If you want blanks to become the sentinel, either quote them in the table or add the sentinel handling in the test.
- Why does @CsvSource({"1, "}) fail against a method declaring (int a, int b)?The blank column is converted to `null`, and `null` cannot be unboxed into the primitive `int`, so argument conversion fails for that invocation. Declaring the parameter as `Integer` fixes it. Because the parameter type is fixed for the whole table, any column that is blank in even one row must be reference-typed.
saying these in an interview costs you the question
- Saying an unquoted empty cell yields an empty String
- Expecting emptyValue to convert unquoted blanks
- Thinking nullValues is needed before any cell can be null
- Using a primitive parameter for a column that is blank in some rows
- Assuming a quoted 'NIL' is still treated as a null token