Junit - mock a file - java

I'm trying to cover code that process a file. I'm trying to avoid using real file for tests, so I'm using Mockito.
This is the code I'm trying to test:
try {
byte[] data = Files.readAllBytes(((File) body).toPath());
immutableBody = data;
actualHeaderParams.put(HttpHeaders.CONTENT_LENGTH, (new Integer(data.length)).toString());
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
I'm using mock file:
File mockedFile = Mockito.mock(File.class);
but I get an Exception on 'toPath'. So I added some path or null, but then again I get Exceptions since the file doesn't exist in the path.
when(mockedFile.toPath()).thenReturn(Paths.get("test.txt"));
getting:
com.http.ApiException: There was a problem reading the file: test.txt
Is there any way doing it without creating a real file for the test?

Since you want to mock reading of files I assume you have some logic in this class which you would like to test in isolation (without using actual files), therefore I suggest to:
Move the responsibility of reading files into a separate class, so instead of having:
byte[] data = Files.readAllBytes(((File) body).toPath());
interleaved with your business logic, have:
byte[] data = fileReader.read(body);
and fileReader will be an instance of your class with a very simple implementation along these lines:
class FileToBytesReader {
byte[] read(File file) throws IOException {
return Files.readAllBytes(((File) body).toPath());
}
}
then in your test you can subsitute fileReader with a mock on which you can set expectations.
If you are using Java 8 you do not have to create the FileToBytesReader class, but you can use java.util.Function:
Function<File, byte[]> fileReader = (file) -> {
try {
return Files.readAllBytes(((File) file).toPath());
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
BTW. If you are working on a legacy code and you cannot change the production code, then you have to use PowerMock to mock this static method.

I'm not sure there is an easy way but I might be wrong. You would probably need to mock the static Files.readAllBytes() method which you would need to use something like PowerMock to do. Or you could wrap this in a method which you can then mock the behaviour of:
public byte[] getAllBytesWrapper(File body) {
return Files.readAllBytes(body.toPath());
}
and then have a mock for this method:
when(classUnderTest.getAllBytesWrapper(any(File.class))).thenReturn("test".getBytes());

Mock Files.readAllBytes() with Matchers.any() as arguments. and return a byte array.

Related

How do i write unit test for function with void return type

I am new to writing Unit tests. I saw few examples of jUnit , but they all were for functions returning a value.
I have to write unit test for following method. Also we are using objects and methods in this method not belonging to this class like ConfigParser and ParseConfig. How do i go about writing Unit tests for such menthods?
#RequestMapping(value = "/generate-json" , consumes = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.POST)
#PageType(pageType = "PlaceHolderPageType")
public void execute(#RequestBody String payload) throws JSONException {
JSONObject json = new JSONObject(payload);
JSONObject configJSON = generateJSONSchema(json.toString());
String capabilityName = (String) configJSON.get(JSONConfigurationConstants.CAPABILITY_NAME);
String fileLocation = FormInputFieldConstants.JSON_PATH + capabilityName + JSONConfigurationConstants.FILE_EXTENSION;
//Write JSON file
try (OutputStreamWriter file = new OutputStreamWriter(new FileOutputStream(fileLocation), StandardCharsets.UTF_8)) {
file.write(configJSON.toString());
file.flush();
file.close();
} catch (IOException e) {
e.printStackTrace();
}
URI uriSchemaLocation = new File(fileLocation).toURI();
ConfigParser configParser = new ConfigParser(uriSchemaLocation);
configParser.parseConfig(TestHelper.getMockedJSONObject(fileLocation));
}
This is the method that you intend to test, correct? I am surprised to see that it contains test code (configParser.parseConfig(TestHelper.getMockedJSONObject(fileLocation));)...
What exactly do you want to test?
You could for example verify the content of the file that gets written by loading that file. However, that accounts only for a part of the method logic.
I don't see any #Override annotation and therefore assume that you are not overriding a method. You could change the method signature to return the parsed config and check it with assertions.
There might be other ways to retrieve the configuration; this depends on the logic of configParser.parseConfig(...).
You could also consider extracting the last tree lines to another method and test that method.
To sum up, you can either change the method to return a result, or extract chunks to own methods and test these, or retrieve the result from another source (in case something like configParser.getParsedConfig() exists).

Writing Strings to a binary file java

I have a list of objects that has some simple String properties. I want to be able to save those strings to binary so that when you open the file outside the program, you only see 1's and 0's.
I have managed to use FileOutputStreamand saved the strings, however, I can't manage to get it to write to binary. The file reads as clean readable text. I have tried getBytes().
What would be the best approach for this? Keep in mind that I want to be able to read the file later and construct back the objects. Would it be better to use Serializable and save a list of objects?
Here is my FileWriter:
NB: The toString() is custom and returns a String with linebreaks for every property.
public class FileWriter {
public void write(String fileName, Savable objectToSave ) throws IOException {
File fileToSave = new File(fileName);
String stringToSave = objectToSave.toString();
byte[] bytesToSave = stringToSave.getBytes(StandardCharsets.UTF_8) ;
try (
OutputStream outputStream = new FileOutputStream(fileToSave);
) {
outputStream.write(bytesToSave);
} catch (IOException e) {
throw new IOException("error");
}
}
}
If your goal is simply serializing, implementing Serializable and writing them would work, but your string is still going to be readable. You can encrypt the stream, but anyone decompiling your code can still devise a way to read the values.

Use mockito and junit to test images

I have a method that gets as parameter a MultipartFile object. Inside the method I use ImageIO.read(some_value) and ImageIO.write(some_value). I want to test this method with a mock image (I don't want to have images stored under the resource folder).
I've tried this:
MockMultipartFile file = new MockMultipartFile("file", "boat.jpg", "image/jpeg", "content image".getBytes()); but without success.
public void f(MultipartFile file) throws IOException {
final BufferedImage read = ImageIO.read(new ByteArrayInputStream(file.getBytes()));
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ImageIO.write(read, "jpg", baos);
}
}
When I run the test the read variable has null value. I think that problem come from "content image".getBytes().
Is there a posibility to use mock images instead of real ones ?
"content image".getBytes() returns a byte[] representation of the String "content image". How is ImageIO supposed to construct a BufferedImage from that?
You have two options here.
Pass a byte[] of real data to MockMultipartFile
Since you mentioned you don't want to use mock image resources, this does not seem like a good fit.
Mock ImageIO's static methods using Powermock
The mocked method will return a real BufferedImage your method can use, without having to read an image from a file.
This gives you the added benefit of being able to mock the call to write() as well, if you wish.
Sample code:
PowerMockito.mockStatic(ImageIO.class);
when(ImageIO.read(any())).thenAnswer(invocation -> {
Object argument = invocation.getArguments()[0];
// here you can check what arguments you were passed
BufferedImage result = new BufferedImage(600, 400, BufferedImage.TYPE_INT_RGB); // create a BufferedImage object
// here you can fill in some data so the image isn't blank
return result;
});
Now, when your method under test calls imageIO.read(), it will receive the BufferedImage you construct in the lambda, without actually reading any files.

How can I use an assertion to test this java code?

My homework assignment is to read a URL and print all hyperlinks at that URL to a file. I also need to submit a junit test case with at least one assertion. I have looked at the different forms of Assert but I just can't come up with any use of them that applies to my code. Any help steering me in the right direction would be great.
(I'm not looking for anyone to write the test case for me, just a little guidance on what direction I should be looking in)
public void saveHyperLinkToFile(String url, String fileName)
throws IOException
{
URL pageLocation = new URL(url);
Scanner in = new Scanner(pageLocation.openStream());
PrintWriter out = new PrintWriter(fileName);
while (in.hasNext())
{
String line = in.next();
if (line.contains("href=\"http://"))
{
int from = line.indexOf("\"");
int to = line.lastIndexOf("\"");
out.println(line.substring(from + 1, to));
}
}
in.close();
out.close();
}
}
Try to decompose your method into simpler ones:
List<URL> readHyperlinksFromUrl(URL url);
void writeUrlsToFile(List<URL> urls, String fileName);
You could already test your first method by saving a sample document as a resource and running it against that resource, comparing the result with the known list of URLs.
You can also test the second method by re-reading that file.
But you can decompose things further on:
void writeUrlsToWriter(List<URL> urls, Writer writer);
Writer createFileWriter(String fileName);
Now you can test your first method by writing to a StringWriter and checking, what was written there by asserting the equality of writer.toString() with the sample value. Not that methods are becoming simpler and simpler.
It would be actually a very good excercise to write the whole thing test-first or even play ping-pong with yourself.
Good luck and happy coding.

Streaming large files with play framework and third party API

I'm writing a play 2 application and I am struggling with a file streaming problem.
I retrieve my files using a third party API with a method having the following signature:
FileMetadata getFile(OutputStream destination, String fileId)
In a traditional Servlet application, if I wanted to send the content to my client I would have done something like:
HttpServletResponse resp;
myService.getFile(resp.getOutpuStream, fileId);
My problem is that in my play 2 Controller class I don't have access to the underlying OuputStream, so the simplest implementation of my controller method would be:
public static downloadFile(String id) {
ByteArrayOutputStream baos = new BAOS(...);
myApi.getFile(baos,id); //Load inside temp Array
ByteArrayInputStream bais = new BAIS(baos.toByteArray())
return Ok(bais);
}
It will work but it requires to load the whole content into memory before serving it so it's not an option (files can be huge).
I was thinking of a solution consisting in:
Defining a ByteArrayOutputStream (baos) inside my controller
Calling the third party API with this baos in parameter
Using the chunk return of the play framework to send the content of
the baos as soon as something is written inside by the 3rd party API
Problem is that I don't know if it possible (call to getFile is blocking so it would require multiple threads with a shared OutputStream) nor if it's overkill.
As someone ever faced this kind of problem and found a solution?
Could my proposed solution solve my problem?
Any insights will be appreciated.
Thanks
EDIT 1
Based on kheraud suggestion I have managed to have a working, but still not perfect, solution (code below).
Unfortunately if a problem occurs during the call to the getFile method, error is not sent back to the client (because I returned Ok) and the browser waits indefinitely for a file that will never come.
Is there a way to handle this case ?
public static Result downloadFile(String fileId {
Thread readerThread = null;
try {
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);
//Reading must be done in another thread
readerThread = new DownloadFileWorker(fileId,pos);
readerThread.start();
return ok(pis);
} catch (Exception ex) {
ex.printStackTrace();
return internalServerError(ex.toString());
}
}
static class DownloadFileWorker extends Thread{
String fileId;
PipedOutputStream pos;
public DownloadFileWorker(String fileId, PipedOutputStream pos) {
super();
this.fileId = fileId
this.pos = pos;
}
public void run(){
try {
myApi.getFile(pos,fileId);
pos.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
EDIT 2
I found a way to avoid infinite loading of the page by simply adding a pos.close in the catch() part of the worker thread. Client ends up with a zero KB file but I guess that's better than an infinite waiting.
There is something in the Play2 Scala framework made for that : Enumerators. This is very close to what you are thinking about.
You should have a look at this doc page for details
I didn't find something similar in the Play2 Java API, but looking in the fw code source, you have a :
public static Results.Status ok(java.io.InputStream content, int chunkSize)
method which seams to be what you are looking for. The implementation can be found in play.mvc.Results and play.core.j.JavaResults classes.
On the Play! mailing list, there recently was a discussion on the same topic:
https://groups.google.com/forum/#!topic/play-framework/YunJzgxPKsU/discussion
It includes a small snippet that allows non-scala-literates (like myself) use the scala streaming interface of Play!.

Categories