How to test this file-writing, 3lines function? - java

This is my method in some service class. It's public so it should be tested. I simply do not know WHAT should I test. I'd mock Writer and spyOn function call, but with this implementation it's impossible (isn't it?)
I'm using Mockito and JUnit
For now, I can only make function to throw and assert that exception
Any help?
#Override
public void initIndexFile(File emptyIndexFile) {
try {
Writer writer = new FileWriter(emptyIndexFile);
writer.write("[]");
writer.close();
} catch (IOException e) {
throw new IndexFileInitializationException(
"Error initialization index file " + emptyIndexFile.getPath()
);
}
}

If you feel that adding the the special content is the business logic and therefore the responsibility of your class, then creating the FileWriter is not (according to the single responsibility pattern.
So you should use a FileWriterFactory that is injected into your Class under Test. Then you can mock that FileWriterFactory to return a mock implementation of the Writer interface on which in turn you can check that it got the expected String.
Your CuT would change to this:
private final WriterFactory writerFactory;
public ClassUnderTest(#Inject WriterFactory writerFactory){
this.writerFactory = writerFactory;
}
#Override
public void initIndexFile(File emptyIndexFile) {
try {
Writer writer = writerFactory.create(emptyIndexFile);
writer.write("[]");
writer.close();
} catch (IOException e) {
throw new IndexFileInitializationException(
"Error initialization index file " + emptyIndexFile.getPath()
);
}
}
and your test to this:
class Test{
#Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
#Mock
private FileWriterFactory fileWriterFactory;
private Writer fileWriter = spy(new StringWriter());
File anyValidFile = new File(".");
#Test
public void initIndexFile_validFile_addsEmptyraces(){
//arrange
doReturn(fileWriter).when(fileWriterFactory).create(any(File.class));
// act
new ClassUnderTest(fileWriterFactory).initIndexFile(anyValidFile);
//assert
verify(fileWriterFactory)create(anyValidFile);
assertEquals("text written to File", "[]", fileWriter.toString());
verify(fileWriter).close();
}
}
in addition you could easily check that your CuT intercepts the IOException:
#Rule
public ExpectedException exception = ExpectedException.none();
#Test
public void initIndexFile_missingFile_IndexFileInitializationException(){
//arrange
doReturnThrow(new IOException("UnitTest")).when(fileWriterFactory).create(any(File.class));
//assert
exception.expect(IndexFileInitializationException.class);
exception.expectMessage("Error initialization index file "+anyValidFile.getPath());
// act
new ClassUnderTest(fileWriterFactory).initIndexFile(anyValidFile);
}
Nice! a factory just to test 3 lines of code! – Nicolas Filotto
This is a good point.
The question is: will there be any method within that class ever interacting with the File object directly and needs to create the FileWriter afterwards?
If the answer is "no" (as it is most likely) following the KISS principle you should inject a Writer object directly instead of the factory and have your methods without the File parameter.
private final Writer writer;
public ClassUnderTest(#Inject Writer writer){
this.writer = writer;
}
#Override
public void initIndexFile() {
try {
writer.write("[]");
writer.close();
} catch (IOException e) {
throw new IndexFileInitializationException(
"Error initialization index file " + emptyIndexFile.getPath()
);
}
}
modified test:
class Test{
#Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
#Rule public ExpectedException exception = ExpectedException.none();
#Mock
private FileWriterFactory fileWriterFactory;
#Mock
private Writer failingFileWriter;
private Writer validFileWriter = spy(new StringWriter());
File anyValidFile = new File(".");
#Test
public void initIndexFile_validFile_addsEmptyraces(){
//arrange
// act
new ClassUnderTest(validFileWriter).initIndexFile();
//assert
verify(fileWriterFactory)create(anyValidFile);
assertEquals("text written to File", "[]", fileWriter.toString());
verify(fileWriter).close();
}
#Test
public void initIndexFile_missingFile_IndexFileInitializationException(){
//arrange
doReturnThrow(new IOException("UnitTest")).when(failingFileWriter).write(anyString());
//assert
exception.expect(IndexFileInitializationException.class);
exception.expectMessage("Error initialization index file "+anyValidFile.getPath());
// act
new ClassUnderTest(fileWriterFactory).initIndexFile(anyValidFile);
}
}

To test that your method can interact with a writer correctly, by sending the correct commands, your pogram has to expose some sort of "seam" so that your test can configure a mock FileWriter. I'm not familiar with mockito but one way would be to encapsulate the FileWriter instantiation behind a method then your test could override that method to return a mock FileWriter.
Assuming that File is an interface:
public Writer getFileWriter(File emptyIndexFile) {
return new FileWriter(emptyIndexFile);
}
This could allow you to override the above method for a test and return a fake Writer
#Override
public Writer getFileWriter(File emptyIndexFile) {
return mockFileWriterInstance;
}
Then your test could make exercise initIndexFile and make assertions on the operations. Using a mock file writer shoudl be trivial to throw IOException so that you can exercise error handling logic.

You could simply provide a temporary file to your method in your test and simply check that it contains [] as expected and once over delete the file.
Something like:
public class FileWritingTest {
// File to provide to the method initIndexFile
private File file;
/* This is executed before the test */
#Before
public void init() throws IOException {
// Create a temporary file
this.file = File.createTempFile("FileWritingTest", "tmp");
// Indicates that it should be removed on exit
file.deleteOnExit();
}
/* This is executed after the test */
#After
public void clean() throws IOException {
// Delete the file once test over
file.delete();
}
#Test
public void testInitIndexFile() throws IOException {
FileWriting fw = new FileWriting();
// Call the method
fw.initIndexFile(this.file);
// Check that the content is [] as expected
Assert.assertEquals("[]", new String(Files.readAllBytes(file.toPath())));
}
}
NB 1: I rely on new String(byte[]) which means that I rely on the default character encoding like you do in your current code but it is not a good practice, we should set a character encoding explicitly to avoid platform dependent.
NB 2: Assuming that you use java 7 or higher, you should consider using the try-with-resources statement to properly close your writer, your code would then be:
public void initIndexFile(File emptyIndexFile) {
try (Writer writer = new FileWriter(emptyIndexFile)) {
writer.write("[]");
} catch (IOException e) {
throw new IndexFileInitializationException(
"Error initialization index file " + emptyIndexFile.getPath()
);
}
}

Mocking a dependency is possible and natural, but mocking an object declared in the body of the method is not natural and tricky.
I imagine 3 solutions:
1) Why, instead of mocking, could you not simply assert that the file is written with the expected character?
It avoids tricks, but it may be redundant and slow if you perform this task very often and you want to unit test them.
2) Making the local variable an instance field to mock it. This seems really a not at all clean solution. If you have multiple methods in the same class that does this kind of processing, you risk to reuse the same writer or to have multiple writer fields. In both cases, you could have side effects.
3) If you perform many write operations and you want to really isolate the call to the writer, you have a solution: redesign your code to have a testable class.
You could extract a dependency to perform the writer processings. The class could provide a method with required parameters to perform instructions. We could call it : WriteService.
public class WriteService {
...
public void writeAndClose(Writer writer, String message){
try {
writer.write(message);
writer.close();
}
catch (IOException e) {
throw new IndexFileInitializationException("Error initialization index file " + emptyIndexFile.getPath());
}
}
}
This class is testable because the writer dependency is a parameter.
And you call the new service like that :
public class YourAppClass{
private WriteService writeService;
public YourAppClass(WriteService writeService){
this.writeService=writeService;
}
#Override
public void initIndexFile(File emptyIndexFile) {
Writer writer = new FileWriter(emptyIndexFile);
writeService.writeAndClose(writer,"[]");
}
}
Now initIndexFile() is also testable by mocking WriteService.
You could check tat writeAndClose() is called on writeService with the good parameter.
Personally, I would use the first solution or the third solution.

Related

Java: How to fix code duplication in multiple methods?

I have some theoretical knowledge related to Design Patterns and now I have some issues to make these info and another ones in action.
I have the following 2 methods in my ServiceImpl class:
#Override
public MultipartFile exportA() throws IOException {
// repeated lines-I same as exportB method (code omitted for brevity)
// other lines special to exportA method
// repeated lines-II same as exportB method (code omitted for brevity)
}
#Override
public MultipartFile exportB() throws IOException {
// repeated lines-I same as exportA method (code omitted for brevity)
// other lines special to exportB method
// repeated lines-II same as exportA method (code omitted for brevity)
}
As it is shown, there are repeated parts in all of these methods. So, should I create 2 methods for repeated lines-I and II, eand then move these code blocks to these newly created 2 methods? Or, is there a better way for Design Patterns?
If I have well understood your statement, this sounds to me a
Builder Pattern that you are looking for. You methods are building a MultipartFile whereas the build process itself depends on 'arguments/parameters' (here I guess sheet file path) and distinct code (the one you referred to as "other lines special to this method").
For that I would create a class MultipartFileBuilder that does the staff and that I would call in each method; of course, by means of setting the appropriate parameters and "code" each time. The code is simply an implementation of the java.util.function.Consumer<T> functional interface used in the following code (*2) and other parameters are using simple setters as well (here (*1)).
Note that I invoked the Consumer<T> as lambda expression here (the c->... construct). And note also that the type parameter <T> in Consumer<T> here is a new class I introduced MultipartFileBuildContext to allow multiple information to be passed to the code you are willing to write in each method. I guest the 'sheet' var would be a starting point. You can add other information if you need to.
To summer up things, this is how the code would look :
#Override
public MultipartFile exportMethodA() throws IOException {
return new MultipartFileBuilder()
.setSheetPath("sheetA/path") (*1)
.setAction(c->{
//(*2) do your staff here for method A
// the "other lines special to this method"
XSSFSheet sheet=c.getSheet()
...
}).build();
}
#Override
public MultipartFile exportMethodB() throws IOException {
return new MultipartFileBuilder()
.setSheetPath("sheetB/path") (*1)
.setAction(c->{
//(*2) do your staff here for method B
// the "other lines special to this method"
XSSFSheet sheet=c.getSheet()
...
}).build();
}
class MultipartFileBuildContext {
private XSSFSheet sheet;
public MultipartFileBuildContext(XSSFSheet sheet){this.sheet=sheet;}
public String getSheetPath() {
return sheetPath;
}
}
class MultipartFileBuilder {
String sheetPath;
Consumer<MultipartFileBuildContext> action;
public String getSheetPath() {
return sheetPath;
}
public MultipartFileBuilder setSheetPath(String sheetPath) {
this.sheetPath = sheetPath;
return this;
}
public Consumer<MultipartFileBuildContext> getAction() {
return action;
}
public MultipartFileBuilder setAction(Consumer<MultipartFileBuildContext> action) {
this.action = action;
return this;
}
public MockMultipartFile build() {
// repeated lines
workbook = new XSSFWorkbook();
sheet = workbook.createSheet(sheetPath);
//
if(action!=null){
MultipartFileBuildContext c=new MultipartFileBuildContext(sheet);
action.accept(c);
}
// repeated lines ======================================================
outputFile = File.createTempFile(...);
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
workbook.write(outputStream);
} catch (IOException e) {
LoggingUtils.error("Writing failed ", e);
}
final FileInputStream input = new FileInputStream(outputFile);
final String fileName = TextBundleUtil.read(...);
return new MockMultipartFile(fileName,
fileName, CONTENT_TYPE, IOUtils.toByteArray(input));
//
}
}
At the end, this pattern needs to be used with care because you need to factorize all that you can to make the builder really useful, but not too much to make it a "boat of anything". For instance, you can have as input the sheet path or an inputstream of it to make it more useful/generic.

Mock testing exceptions handling

Description: I want to unit test method that implements interface. Method retrieves data from files, hence potentially throws exceptions. Code that actually retrieves data is Files.readAllLines(Paths.get(fileName)); and this piece forces me to handle IOException. There are also two other classes that uses interface FileLinesReader to retrieve data. Everything works fine, code does what's expected. However when I run the whole code with invalid file name (that doesn't exist in any location), NoSuchFileException is thrown which in my understanding is thrown by Paths.get(fileName). I want to properly handle exceptions which can most likely occur during code execution.
Code:
public interface FileLinesReader {
List<String> readAllLines(String fileName);
}
public class DefaultFileLinesReader implements FileLinesReader {
String defaultFile;
public DefaultFileLinesReader(String defaultFile) {
this.defaultFile = defaultFile;
}
#Override
public List<String> readAllLines(String fileName) {
List<String> linesOutput;
try {
linesOutput = Files.readAllLines(Paths.get(fileName));
}
catch(IOException e) {
System.err.println("Provided file: \"" + fileName + "\" does not exist. Default file: " + defaultFile);
e.printStackTrace();
System.err.println("Do you want to use default file? [y/n]");
try(Scanner scanner = new Scanner(System.in)) {
while(true) {
String input = userInput(scanner);
if (input.equals("y")) {
try {
linesOutput = Files.readAllLines(Paths.get(defaultFile));
break;
}
catch (IOException ex) {
throw new RuntimeException("Default file not defined!", ex); //Should never be thrown. Default file must exist in MessageSender folder.
}
}
//Default file must exist in designated folder.
//If no file selected, execution is ceased.
if (input.equals("n")) {
throw new RuntimeException("No file selected.");
}
System.out.println("Invalid command.");
System.out.println("Do you want to use default file? [y/n]");
}
}
}
return linesOutput;
}
//Created to define input in unit tests
protected String userInput(Scanner scanner) {
return scanner.next();
}
}
Problem: I want to use Mockito to test this class but apparently I still don't understand mocking enough. I want to spy method for setting up user input, and then also by spying throw RuntimeException as I would like to cease code execution. What I get in result is like my code is executing normally, not as a test. try-catch block is executed but message I get is that NoSuchFileException has been thrown. It reaches to the moment when user can enter command, but spying method that should pass "n" as input definitely doesn't work. This is where I get really confused. I'm not sure if I catch exceptions correctly. I've tried to create separate method only for Paths.get(fileName) so I could mock it too but I got a feeling that code get's more cumbersome because of it. What I have now is code like this:
#ExtendWith(MockitoExtension.class)
class DefaultFileLinesReaderTest {
private static final String FAKE_FILE = "fakeFile";
private DefaultFileLinesReader defaultFileLinesReaderTest;
private DefaultFileLinesReader defFileLinesReaderSpy;
#BeforeEach
void setUp() {
defaultFileLinesReaderTest = new DefaultFileLinesReader(FAKE_FILE);
defFileLinesReaderSpy = spy(defaultFileLinesReaderTest);
}
#Test
void readAllLines_RuntimeException() {
Scanner scanner = mock(Scanner.class);
when(defFileLinesReaderSpy.userInput(scanner)).thenReturn("n");
when(defFileLinesReaderSpy.readAllLines(FAKE_FILE)).thenThrow(new RuntimeException());
assertThrows(RuntimeException.class, () -> defFileLinesReaderSpy.readAllLines(FAKE_FILE));
}
}
And the output when running test is like this:
Provided file: "fakeFile" does not exist. Default file: fakeFile
java.nio.file.NoSuchFileException: fakeFile
\\stacktrace here
Do you want to use default file? [y/n]
Question: How can I test if exceptions thrown in readAllLines method are handled as I expected?
Normally, you would throw a subclass of RuntimeException, you may think of using IllegalArgumetException.
For unit tests, you should have test methods to test the normal behavior of your class method and other test methods for testing thrown exceptions cases.
To test the cases, where an exception might be thrown, you can consider this example (JUnit 4):
#Rule
public ExpectedException exceptionRule = ExpectedException.none();
#Test
public void shouldThrowException() {
exceptionRule.expect(IllegalArgumentException.class);
exceptionRule.expectMessage("Your exception message");
}
And if you just want to check the thrown exception type you can simply use :
#Test(expected = IllegalArgumentException.class)
public void shouldthrowException() {
// Call method
}

Argument(s) are different! Wanted:

I am writing a unit test for my below code
public class Class1 {
protected void execute(String a, String b) {
try{
process(a,b);
}
catch(Exception E){
Class2.write(e,Class1.class.getSimpleName())
}
}
private void process(String a, String b) {
validate(a,b);
// Doing some processing on a and b values
}
private void validate (String a, String b) {
if(a==null || a.isEmpty() || b==null || b.isEmpty())
throw new IllegalArgumentException("Input value cannot be null or empty");
}
}
For the above code, I am trying to write a UT which covers the exception use case. Below is my UT code,
#Test
public void test1(){
try {
PowerMockito.mockStatic(Class2.class);
PowerMockito.when(Class2.class, "write", Mockito.anyObject(), Mockito.anyString())
.thenCallRealMethod();
Class1 class1 = new Class1();
Class2.write(new IllegalArgumentException("Input value cannot be null or empty"),Class1.class.getSimpleClassName());
PowerMockito.verifyStatic(Class2.class, VerificationModeFactory.times(1));
class1.execute(Mockito.anyString(),Mockito.anyString());
} catch (Exception e) {
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
I am getting the below exception when I execute the above test
Argument(s) are different! Wanted:
Class2.write{
java.lang.IllegalArgumentException:Input value cannot be null or empty,
Class1
}
Actual invocation has different arguments:
Class2.write{
java.lang.IllegalArgumentException:Input value cannot be null or empty,
Class1
}
Can someone please help me on resolving this issue?
I really appreciate your help and time
Thanks in Advance
Your Problem:
IllegalArgumentException does not use the string message for equality. It would be safer to test the string message or the class type. I would prefer that the test detect the type rather than the message, as the string message should not be used for control flow, it is an implementation detail.
System.out.println(Objects.equals(
new IllegalArgumentException(),
new IllegalArgumentException()));
// false
System.out.println(Objects.equals(
new IllegalArgumentException().getClass(),
new IllegalArgumentException().getClass()));
// true
So to mock this I would use matchers:
any(IllegalArgumentException.class), eq(Class1.class.getSimpleName())
Issues with your design:
I'm going to end with an argument against how this code is structured, being that it is not built around dependency injection. Rather than calling the static method Class2::write, you could be calling an instance method.
For example, create the interface:
public interface Writer {
void write(Exception e, String source);
}
You can now refactor the class to provide two ctors, one that accepts any writer, and one that defaults to Class2.
public class Class1 {
private final Writer writer;
public Class1() {
this(Class2::write);
}
public Class1(Writer writer) {
this.writer = writer;
}
protected void execute(String a, String b) {
try {
process(a,b);
}
catch (Exception E) {
writer.write(e, Class1.class.getSimpleName());
}
}
...
}
Using this strategy you can now simply create an instance mock of Writer. This avoids having to mock as static method which changes the bytecode of your application, and also make your class more flexible as it can support many different writer implementations now. Anything that is modifying the bytecode of the application should be used very sparingly, such as replacing static method calls, does not truly validate the runtime execution of your code.
In my opinion, the majority of the PowerMockito/PowerMock only help verify code which was not built with testability / flexibility in mind. You shouldn't need to use anything outside of the Mockito/EasyMock tool-set for well structured code. There are some exceptions but the tool-set should be used very sparingly.

Writing Junit test to cover exception and catch block

I have written Junit test case for following function. When checked JACOCO test coverage. It is showing only try block is covered by test case. I am newbie to writing test cases. How the exceptions and catch block can be covered in test cases
Here is a method
public static List<Student> readCsvFile(String fileName)
{
BufferedReader fileReader = null;
//logic to read file
}
catch (Exception e)
{
System.out.println("Error in CsvFileReader !!!");
e.printStackTrace();
} finally
{
try
{
fileReader.close();
} catch (IOException e)
{
System.out.println("Error while closing fileReader !!!");
e.printStackTrace();
}
}
return students;
}
And TestMethod
#Test
public void ReadCsvFileTest()
{
String fileName = "test.csv";
List<Student> result = new ArrayList<Student>();
result = CsvFileReader.readCsvFile(fileName);
Student student1 = null;
Iterator<Student> it = result.iterator();
while (it.hasNext())
{
Student s = it.next();
if ("471908US".equals(s.getId()))
{
student1 = s;
break;
}
}
assertTrue(student1 != null);
}
In such situations you may often consider the introduction of additional dependencies to your class. Here is what I mean with a rough example. Create a factory for readers:
interface BufferedReaderFactory
{
public BufferedReader createBufferedReader(String fileName) throws IOException;
}
Then you will have a trivial implementation that hardly needs any testing, e.g. something similar:
class BufferedReaderFactoryImpl implements BufferedReaderFactory
{
#Override
public BufferedReader createBufferedReader(String fileName) throws IOException
{
return new BufferedReader(new FileReader(fileName));
}
}
Then you have to find a way to inject this dependency into your class. I usually use Guice in my daily work but you may try something as simple as using constructor injection and making your method non static. Here is an example:
class CsvFileReader
{
private final BufferedReaderFactory factory;
public CsvFileReader(BufferedReaderFactory factory)
{
this.factory = factory;
}
public List<Student> readCsvFile(String fileName)
{
BufferedReader fileReader = null;
try
{
fileReader = factory.createBufferedReader(fileName);
...
}
catch(IOException e)
{
...
}
finally
{
...
}
return new LinkedList<>();
}
}
With a mocking framework like Mockito the behavior of this class in case of IOException-s is easier to test now (note that you may also return mocks that throw exceptions from the factory). Here is a sample:
#RunWith(MockitoJUnitRunner.class)
public class MyTest
{
#Mock
private BufferedReaderFactory mockFactroy;
#Test
public void testIOException() throws IOException
{
String ivalidFileName = "invalid.txt";
//throw exception in case that invalid file name is passed to the factory
Mockito.when(mockFactroy.createBufferedReader(ivalidFileName)).thenThrow(new IOException("Hello!"));
CsvFileReader csvFileReader = new CsvFileReader(mockFactroy);
//invoke with a factory that throws exceptions
csvFileReader.readCsvFile(ivalidFileName);
//...
//and make a sensible test here, e.g. check that empty list is returned, or proper message is logged, etc.
}
}
You may do that without Mockito, of course - by implementing a test factory. But this is more cumbersome especially in more complicated use cases. Once the IOException is thrown you will get appropriate coverage report by JaCoCo.
Also mind a limitation of JaCoCo mentioned here, in section Source code lines with exceptions show no coverage. Why?
Given the current signature of your method under test, getting to full coverage isn't easy: your catch block is only executed when an exception is thrown within your try block.
One way to solve this: do not pass in the file name, but the reader object itself. Like:
public static List<Student> readCsvFile(String fileName) {
return readCsvFile(new BufferedReader(fileName));
}
static List<Student> readCsvFile(BufferedReader reader) {
try {
...
} catch( ...
Now you can write several specific unit tests for that second method. You keep your tests that simply do "correct" reading; but you add one where you pass in a mocked reader object ... that simply throws an Exception at some point. Please note that I made that new method just package protected - you probably don't want to use that "public"; and making it private would prevent it from being unit tested.
That should help you achieving full coverage. Of course you will also need at least one test to "cover" the string-taking method, too.
Some notes:
Be careful about re-inventing the wheel. There are many existing CSV parsers already. And be assured: writing a correct CSV parser that is able to deal with all "correct" input CSV is much harder than it sounds. If this is not for "learning purposes" I strongly advise to not write your own CSV parser.
Be careful about making such things static. As said, a real CSV parser is a complicated thing, and worth its complete own class. So no static helper methods - a normal class which you instantiate to then call methods on it (that would also for using dependency injection which would help with the problem you are asking about ... getting exceptions thrown within try blocks)
You are catching Exception in your code example. Don't do that - try to catch exactly those exceptions that your code can actually produce (probably IOException in your case).

Test Class using File and FileInputStream with Mockito/PowerMockito [duplicate]

This question already has answers here:
How do I unit-test saving file to the disk?
(3 answers)
Closed 8 years ago.
I would like to mock a File and FileInputStream Object for an JUnit test.
Let us say we are having a Parser. From outside the Parser is just accessible via the parse(File myFile) method. The other methods like readMyStream....are private.
Example Code:
public class Parser {
public HashMap<String, String> parse(File myFile) throws Exception {
HashMap<String, String> myConfig;
Config config;
try {
//this line gives me a headache
FileInputStream myFileInputStream = new FileInputStream(myFile);
configStream = readMyStream(myFileInputStream);
..........
} catch (FileNotFoundException e) {
throw e;
}
return myConfig;
}
//reads the stream
private Config readMyStream(FileInputStream myFileInputStream) {
Config config;
...JDOM stuff....
return config;
}
}
The problems I face:
how to assert a File Object an FileInputStream (PowerMockito) like this File belongs to this FileInputStream with the following content
how to mock a private method (Mockito/PowerMockito)
an example of the Mocking/not working :)....
public class ParserTest {
#Test
public final void testParse() {
File MOCKEDFILE = PowerMockito.mock(File.class);
PowerMockito.when(MOCKEDFILE.exists()).thenReturn(true);
PowerMockito.when(MOCKEDFILE.isFile()).thenReturn(true);
PowerMockito.when(MOCKEDFILE.isDirectory()).thenReturn(false);
PowerMockito.when(MOCKEDFILE.createNewFile()).thenReturn(true);
PowerMockito.when(MOCKEDFILE.length()).thenReturn(11111111L);
//what about the path of MOCKEDFILE which isn't existing
PowerMockito.when(MOCKEDFILE.getPath()).thenReturn(?????);
//how to assign a File an FileInputStream? (I thought something like)
PowerMockito.mockStatic(FileInputStream.class);
FileInputStream MOCKEDINPUTSTREAM = PowerMockito.mock(FileInputStream.class);
PowerMockito.whenNew(FileInputStream.class).withArguments(File.class).thenReturn(MOCKEDINPUTSTREAM);
//how to mock the private method readMyStream
}
Rather than mocking File, I would suggest using the TemporaryFolder Rule and create / not create the file as appropriate.
In my previous projects, we have written a FileInputStreamSupplier class that is used to create a FileInputStream. This class can then be mocked to provide a mocked FileInputStream to allow for testing behavior. Generically, you could have your class take a Supplier<FileInputStream> (using Guava) and mock that.

Categories