Spring Boot - Throwing IOException when mocking BufferedReader - java

I am currently trying to test a service in Spring Boot. It should read a file from a BufferedReader. The first test works just fine, but the one where I try to mock the IOException is not.
HTMLService:
#MockBean
HTMLService htmlService;
public String read(String fileName, String username) {
String s = null;
String filePath = new File("").getAbsolutePath();
String path = filePath+"/src/main/resources/html/"+fileName;
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
String line = br.readLine();
StringBuilder sb = new StringBuilder();
while (line != null) {
sb.append(line).append("\n");
line = br.readLine();
}
s = sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
s = s.replace("KINO-USERNAME", username);
return s;
}
Test:
#Test
void testReadException() {
when(htmlService.read("Registration.html", "DrBackmischung")).thenReturn("Test");
try {
BufferedReader br = Mockito.mock(BufferedReader.class);
when(br.readLine()).thenThrow(IOException.class);
} catch (IOException e) {
e.printStackTrace();
}
assertThrows(IOException.class, new Executable() {
#Override
public void execute() throws Throwable {
htmlService.read("Registration.html", "DrBackmischung");
}
});
}
I've tried mocking it different ways, but nothing seems to work. Is there a working approach?

It seems you are mocking BufferedReader, however the BufferedReader used inside your HTMLService class is new BufferedReader, so it is initializing a new instance of BufferedReader, and definitley not pointing towards your mock instance..
Why dont you just mock the return of the read method() to throw IOException instead.
when(htmlService.read("Registration.html", "DrBackmischung")).thenThrow(IOException.class);
Honesty I cant see the validity of such a test (Towards that a BufferedReader throws an IOException)..unless you have an important business logic (Another method/Service, that could be impacted), but testing an isolated IOException doesnt seem to provide any benefit.

Related

catch block not covered in unit testing

I have written a test case for the exception is passed but does not cover code coverage.
Please help me I tried many ways but doesn't resolve.
public String checkJiraStatus(HttpURLConnection httpURLConnection) throws IOException {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
String inputLine;
StringBuilder stringBuilder = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
stringBuilder.append(inputLine);
}
in.close();
JSONObject jsonObject = new JSONObject(String.valueOf(stringBuilder));
JSONObject fields = (JSONObject) jsonObject.get("fields");
JSONObject status = (JSONObject) fields.get("status");
return (String) status.get("name");
}catch (IOException |JSONException ioException) {
throw new IOException("Problem while fetching the data"+ioException.getMessage());
}
}
test case passes correctly but didn't give code coverage.
#Test(expected = Exception.class)
public void testIoException() throws Exception {
when(mockJiraFunctions.checkJiraStatus(any())).thenThrow(new
IOException("Problem while fetching the data"));
jiraFunctions.checkJiraStatus(any());
}
As I mentioned in comment, you should run your real method to have a coverage.
And you should make a situation, where your function will throw an exception. For example in your case you can make a mock object of HttpURLConnection class and make him throw IOException when you call getInputStream() method on it.
So your test will be like
#Test(expected = Exception.class)
public void test() {
HttpURLConnection connectionMock = mock(HttpURLConnection.class);
when(connectionMock.getInputStream()).thenThrow(new IOException());
jiraFunctions.checkJiraStatus(connectionMock);
}

Junit Test for InputStreamReader with Mockito

Can you please help me in writing the Junit test case for the below code?
public class ConsoleReader implements InputReader {
public Cell readInput() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter the co-ordinate Seperated by Comma");
String coOrdinates = reader.readLine();
String[] values=coOrdinates.split("\\,");
return new Cell(Integer.parseInt(values[0]),Integer.parseInt(values[1]));
} catch (IOException ioe) {
ioe.printStackTrace();
}
return null;
}
}
Extract the reader as a field. (You can initiaize it either directly or in constructor)
private final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Define a getter (either public or protected)
protected BufferedReader getReader(){
return reader;
}
Remove initialization of new BufferedReader(...) from your method. Retrieve it using getReader() instead.
public Cell readInput() {
try {
System.out.print("Enter the co-ordinate Seperated by Comma");
String coOrdinates = getReader().readLine();
String[] values=coOrdinates.split("\\,");
return new Cell(Integer.parseInt(values[0]),Integer.parseInt(values[1]));
} catch (IOException ioe) {
ioe.printStackTrace();
}
return null;
}
In your test class initialize your ConsoleReader as Mockito.spy
ConsoleReader consoleReader = spy(new ConsoleReader());
Mock your getter
private BufferedReader bufferedReader = mock(BufferedReader.class);
#Before
public void setUp() {
doReturn(bufferedReader).when(consoleReader).getReader();
doCallRealMethod().when(consoleReader).readInput();
}
Define your test:
#Test
public void testReadInput() {
when(bufferedReader.readLine()).thenReturn("123,456");
Cell expectedCell = new Cell(123, 456);
Cell actualCell = consoleReader.readInput();
assertEquals(expectedCell, actualCell);
}
You can use Mockito to mock the BufferedReader, like the example below.
BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
Mockito.when(bufferedReader.readLine()).thenReturn("1", "2", "3");
// You can mock the result based on the type of result you are expecting.

Good practice with Mockito And BufferedReader

I'm trying to test a class that makes File/Stream treatment. For instance, the method readFile will use BufferedReader to return an ArrayList of String with every lines of the file inside:
public ArrayList<String> readFile(String fileName)
{
ArrayList<String> result = new ArrayList<String>();
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(STORAGE_DIRECTORY+fileName);
br = new BufferedReader(fr);
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
result.add(sCurrentLine);
}
}
catch (FileNotFoundException e) {
return new ArrayList<String>();
} catch (IOException e) {
return new ArrayList<String>();
}
br.close();
fr.close();
return result;
}
But when I use Mockito in order to mock bufferedReader method "readLine()",a FileNotFoundException is thrown because of FileReader constructor. Must I use temporaryFile or Mock FileReader constructor ?
#Test
public void readFileTest5() throws Exception {
BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
FileReader fileReader = Mockito.mock(FileReader.class);
when(BufferedReader.readLine()).thenReturn("abc");
assertEquals("",new ArrayList<String>(), FileUtil.readFile("abc"));
}
Thank you
In readFile BufferedReader wraps FileReader and FileReader is created inside that method so you have no opportunity to mock FileReader which means that you have no way to mock the inputs into your BufferedReader instance.
This approach makes testing difficult.
I'd suggest changing your approach. For example:
public ArrayList<String> readFile(BufferedReader reader) {
// ...
}
Then your test could be:
#Test
public void readFileTest() throws Exception {
BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
Mockito.when(bufferedReader.readLine()).thenReturn("a", "b", "c", null);
List<String> expected = Arrays.asList("a", "b", "c");
Assert.assertEquals("", expected, readFile(bufferedReader));
}
Or without Mockito at all:
#Test
public void readFileTest() throws Exception {
BufferedReader bufferedReader = new BufferedReader(new StringReader("a\nb\nc"));
List<String> expected = Arrays.asList("a", "b", "c");
Assert.assertEquals("", expected, readFile(bufferedReader));
}
Another approach would be to create an actual file and read it i.e. no need for mocking anything. You could use JUnit's Temporary Folder Rule to help clean up after the test.
On a separate note: the readFile() isn't closing the BufferedReader and FileReader safely.
Since your FileUtil does read a file referenced by name, you do need to create a file in the file system. This is easily done by
File tempFile = File.createTempFile("temp", ".tmp");
tempFile.deleteOnExit(true);
some words on your implementation code:
ArrayList<String> result = new ArrayList<String>();
// combine directory and file name like this
File f = new File(STORAGE_DIRECTORY, fileName);
// use try-with-resource here, like this:
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
result.add(sCurrentLine);
}
} catch (FileNotFoundException e) {
// no need to create a new list
return Collections.emptyList()
} catch (IOException e) {
return Collections.emptyList()
}
// you don't need to close the reader if you use try-with-resource
return result;
}
You can of course just use Files#readAllLines.
try {
return Files.readAllLines(Paths.get(STORAGE_DIRECTORY, fileName), StandardCharsets.UTF-8);
} catch (IOException e) {
return Collections.emptyList();
}

Why i get unicode from html?

I wrtite parser without third-party libraries. Get html code from web site - http://www.cnn.com/ - but some part of code has unicode instead symbols, for example: "\u003cbr/>Sign in to your TV service provider to get access to \u003cbr/>" i think it is problem with encode - how i can fix it? Sorry for my English. Thank you.
public class Main {
public static void main(String[] args) throws IOException {
String commandLine = Scraper.readLineFromConsole();
Reader reader = Scraper.getReader(commandLine);
Scraper.writeInFileFromURL(reader);
}
public static class Scraper {
public static void writeInFileFromURL(Reader out) {
Reader reader = out;
BufferedReader br = new BufferedReader(reader);
try {
PrintWriter writer = new PrintWriter("newFile.txt");
String htmltext;
while (br.ready()) {
htmltext = br.readLine();
writer.write(new String(htmltext));
}
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String readLineFromConsole() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String commandLine = null;
try {
commandLine = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return commandLine;
}
public static Reader getReader(String url)
throws IOException {
// Retrieve from Internet.
if (url.startsWith("http:") || url.startsWith("https:")) {
URLConnection conn = new URL(url).openConnection();
return new InputStreamReader(conn.getInputStream());
}
// Retrieve from file.
else {
return new FileReader(url);
}
}
}
}

Read utf-8 url to string java

Good day. Have just switched from objective-c to java and trying to read url contents normally to string. Read tons of posts and still it gives garbage.
public class TableMain {
/**
* #param args
*/
#SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
URL url = null;
URLConnection urlConn = null;
try {
url = new URL("http://svo.aero/timetable/today/");
} catch (MalformedURLException err) {
err.printStackTrace();
}
try {
urlConn = url.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader input = new BufferedReader(new InputStreamReader(
urlConn.getInputStream(), "UTF-8"));
StringBuilder strB = new StringBuilder();
String str;
while (null != (str = input.readLine())) {
strB.append(str).append("\r\n");
System.out.println(str);
}
input.close();
} catch (IOException err) {
err.printStackTrace();
}
}
}
What's wrong? I get something like this
??y??'??)j1???-?q?E?|V??,??< 9??d?Bw(?э?n?v?)i?x?????Z????q?MM3~??????G??љ??l?U3"Y?]????zxxDx????t^???5???j?‌​?k??u?q?j6?^t???????W??????????~?????????o6/?|?8??{???O????0?M>Z{srs??K???XV??4Z‌​??'??n/??^??4????w+?????e???????[?{/??,??WO???????????.?.?x???????^?rax??]?xb??‌​& ??8;?????}???h????H5????v?e?0?????-?????g?vN
Here is a method using HttpClient:
public HttpResponse getResponse(String url) throws IOException {
httpClient.getParams().setParameter("http.protocol.content-charset", "UTF-8");
return httpClient.execute(new HttpGet(url));
}
public String getSource(String url) throws IOException {
StringBuilder sb = new StringBuilder();
HttpResponse response = getResponse(url);
if (response.getEntity() == null) {
throw new IOException("Response entity not set");
}
BufferedReader contentReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = contentReader.readLine();
while ( line != null ){
sb.append(line)
.append(NEW_LINE);
line = contentReader.readLine();
}
return sb.toString();
}
Edit: I edited the response to ensure it uses utf-8.
This is a result of:
You are fetching data that is UTF-8 encoded
You are didn't specify, but I surmise you are printing it to the console on a Windows system
The data is being received and stored correctly, but when you print it the destination is incapable of rendering the Russian text. You will not be able to just "print" the text to stdout unless the ultimate display handler is capable of rendering the characters involved.

Categories