I am trying to test exception handling when using Opencsv's CSVReader. The data will be coming from a String. It's not working because I am (probably) not properly mocking the CSVReader, but cannot quite figure out what I need to do.
Here's the class
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.exceptions.CsvValidationException;
// other imports skipped
public class MyCsvReader {
private Path contentsAsString;
private CSVReader csvReader;
public MyCsvReader(final String contentsAsString) {
InputStream inputStream = new ByteArrayInputStream(contentsAsString.getBytes());
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
csvReader = new CSVReaderBuilder(inputStreamReader)
.withSkipLines(0)
.withKeepCarriageReturn(false)
.build();
}
public void readData() {
String[] line;
try {
while ((line = csvReader.readNext()) != null) {
System.out.println("line:" Arrays.toString(line));
}
} catch (IOException e) {
System.out.println("got IOException");
// I will be throwing a custom exception here
throw new RuntimeException(e);
} catch (CsvValidationException e) {
System.out.println("got CsvValidationException");
// and a different custom exception here
throw new RuntimeException(e);
}
}
}
and the test
public class MyCsvReaderTest {
@Test
public void testException() throws Exception {
String[] rows = {
"column1,column2,column3",
"test,abc,def"
};
String rowData = String.join("\n", rows);
CSVReader mock = Mockito.mock(CSVReader.class);
Mockito.when(mock.readNext()).thenThrow(new IOException("test"));
MyCsvReader reader = new MyCsvReader(rowData);
try {
reader.readData();
fail("Expected an exception, but call succeeded");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
When I run it, reader.readNext()
does not throw an exception
line: [column1, column2, column3]
line: [test, abc, def]
org.opentest4j.AssertionFailedError: Expected and exception, but call succeeded
... stack trace deleted
Suggestions on what I need to do? Thanks!
CodePudding user response:
You don't use a mocked instance but a real one.
If the goal here is throw an exception when mock.readNext()
happens you have to do something like this in order to inject your mocked instance of CSVReader
:
public class MyCsvReader {
private final CSVReader csvReader;
public MyCsvReader(final CSVReader csvReader) {
this.csvReader = csvReader;
}
public MyCsvReader(final String contentsAsString) {
this(getCsvReader(contentsAsString));
}
private static CSVReader getCsvReader(final String contentsAsString) {
InputStream inputStream = new ByteArrayInputStream(contentsAsString.getBytes());
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
return new CSVReaderBuilder(inputStreamReader)
.withSkipLines(0)
.withKeepCarriageReturn(false)
.build();
}
public void readData() {
String[] line;
try {
while ((line = csvReader.readNext()) != null) {
System.out.println("line:" Arrays.toString(line));
}
} catch (IOException e) {
System.out.println("got IOException");
// I will be throwing a custom exception here
throw new RuntimeException(e);
} catch (CsvValidationException e) {
System.out.println("got CsvValidationException");
// and a different custom exception here
throw new RuntimeException(e);
}
}
}
public class MyCsvReaderTest {
@Test
public void testException() throws Exception {
CSVReader mock = Mockito.mock(CSVReader.class);
Mockito.when(mock.readNext()).thenThrow(new IOException("test"));
MyCsvReader reader = new MyCsvReader(mock);
try {
reader.readData();
fail("Expected an exception, but call succeeded");
} catch (RuntimeException ignored) {
}
}
}