Search code examples
javafileunit-testingjunitpowermockito

Mocking file operations in a unit test using junit and PowerMockito doesn't work


I'm trying to write unit test for a static method which contains file operations. I'm using junit and PowerMockito. The method to be test is converting a csv file to bean list. Since this is unit test I mock a method call which is inside of our method. But the following error is occuring,

org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods declared on non-public parent classes is not supported. 2. inside when() you don't call method on mock but on some other object.

at com.mypackage..unittest.UTCSVBeanUtil.convert_convertingCsvToBean(UTCSVBeanUtil.java:54) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)

My class is,

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;

import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;
import au.com.bytecode.opencsv.bean.ColumnPositionMappingStrategy;
import au.com.bytecode.opencsv.bean.CsvToBean;

public class CSVBeanUtil {

public static <T> List<T> fileToBean(final String filename, final char delimiter, final Class<T> beanClass,
        final String[] columns) throws FileNotFoundException {
    BufferedReader reader = new BufferedReader(new FileReader(filename));
    try {
        return bufferReaderToBean(reader, delimiter, beanClass, columns);
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (final IOException e) {
                // ignore
            }
        }
    }
}

public static <T> List<T> stringToBean() {
    return null;
}

public static <T> List<T> bufferReaderToBean(BufferedReader reader, final char delimiter, final Class<T> beanClass,
        final String[] columns) {
    CSVReader csvreader = null;
    final CsvToBean<T> csv = new CsvToBean<T>();
    csvreader = new CSVReader(reader, delimiter);
    ColumnPositionMappingStrategy<T> strategy = new ColumnPositionMappingStrategy<T>();
    strategy.setType(beanClass);
    strategy.setColumnMapping(columns);
    return csv.parse(strategy, csvreader);
}

public static boolean writeToCsv(List<String[]> beanList, Path absPath) throws IOException {
    CSVWriter writer = new CSVWriter(new FileWriter(absPath.toAbsolutePath().toString()),
            CSVWriter.DEFAULT_SEPARATOR, CSVWriter.NO_QUOTE_CHARACTER);
    writer.writeAll(beanList);
    writer.close();
    return false;
}

}

And my test class is,

import static org.junit.Assert.assertEquals;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import com.mypackage..config.AppConfig;
import com.mypackage..entity.MyFile;
import com.mypackage..service.MyFileValidation;
import com.mypackage..utility.CSVBeanUtil;

import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

@WebAppConfiguration
@ContextConfiguration(classes = { AppConfig.class })
@PrepareForTest(CSVBeanUtil.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UTCSVBeanUtil {
List<MyFile> dataList = new ArrayList<MyFile>();
List<MyFile> expectedList=new ArrayList<MyFile>();

@Before
public void beforeClass() {
    expectedList = getdataList();
}

@Test
public void convert_convertingCsvToBean()
        throws IOException{
    PowerMockito.mockStatic(CSVBeanUtil.class);
//      BufferedReader bufferedReader = Mockito.mock(BufferedReader.class); // while using this the test execution doesn't terminate  
    BufferedReader bufferedReader= new BufferedReader(new StringReader("201030"));
//      File file = Mockito.mock(File.class);
    Mockito.when(CSVBeanUtil.bufferReaderToBean(bufferedReader, ',', MyFile.class, MyFile.columns))
            .thenReturn(expectedList);
    dataList.addAll(CSVBeanUtil.fileToBean( null, ',', MyFile.class, MyFile.columns));
    assertEquals(expectedList,dataList);
}

private List<MyFile> getdataList() {
    List<MyFile> expectedList=new ArrayList<MyFile>();
    MyFile gv=new MyFile();
    gv.setTRADENUM("201030");
    expectedList.add(gv);
    return expectedList;
}

}

I'm trying to solve this problem. Please help me... Thank You


Solution

  • PowerMock provides it's own runner, specified with the @RunWith annotation

    @RunWith( PowerMockRunner.class)
    

    If you want to use SpringJUnit4ClassRunner.class

    @RunWith(PowerMockRunner.class)
    @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
    

    Using another JUnit Runner with PowerMock