如何单元测试并模拟将文件作为参数的方法

时间:2015-11-16 20:04:01

标签: java unit-testing junit mockito

我有一个类CollectionObject,它创建一个ArrayList。

public class CollectionObject {

    private List<String> collectionObject;

    public CollectionObject() {
        collectionObject = new ArrayList<String>();
    }

    public List<String> getCollectionObject() {
        return collectionObject;
    }

    public void add(final String stringToWrite) throws VerifyException {
        collectionObject.add(stringToWrite);
    }
}

还有另一个类,它接受类CollectionObject并使用它将文件的内容写入类CollectionObject。

public class ReaderFileWriterObjectService {

    private BufferedReader bufferedReader;
    private CollectionObject collectionObject;
    private String line;

    public CollectionObject getCollectionObjectAfterWritingFromAFile(final File file)
            throws VerifyException, IOException {
        collectionObject = new CollectionObject();
        bufferedReader = new BufferedReader(new FileReader(file));
        while ((line = bufferedReader.readLine()) != null) {
            collectionObject.add(line);
        }
        bufferedReader.close();
        return collectionObject;
    }

如何测试和模拟类ReaderFileWriterObjectService的方法?

6 个答案:

答案 0 :(得分:4)

让我补充@LouisWasserman's answer

您无法测试依赖java.io.File的API;此类无法进行可靠的单元测试(即使它在JDK级别上甚至不是final)。

但是新的文件系统API并不是这种情况,它出现在Java 7中。

也称为JSR 203,此API为任何提供&#34;文件系统对象的存储介质提供统一的API&#34;。

短篇小说:

  • a&#34; filesystem object&#34;由此API中的Path实现;
  • 任何实现JSR 203的JDK(即任何Java 7+版本)都支持此API;
  • 要从默认 FileSystem上的资源获取路径,您可以使用Paths.get();
  • 但你不仅限于此。

简而言之,在您的API 测试用例中,您应该使用Path,而不是File。如果要测试与某些文件系统资源相关的任何内容,请使用JDK的Files类来测试Path个实例。

可以从主要的基于磁盘的文件系统中创建FileSystem。建议:使用this

答案 1 :(得分:2)

我正在做同样的事情,以下想法正在发挥作用, 我希望这对你也有用,

 @InjectMocks
 private CollectionObject collectionObject;

@Test
public void getCollectionObjectAfterWritingFromAFile() throws Exception {
    CollectionObject  expectedObject =new CollectionObject();
    List<String> expectedList=new ArrayList<String>();
    expectedList.add("100");

    CollectionObject  resultObject =new CollectionObject();

    BufferedReader reader=new BufferedReader(new StringReader("100"));
    PowerMockito.mock(BufferedReader.class);
    PowerMockito.mock(FileReader.class);
    PowerMockito.whenNew(FileReader.class).withArguments("test10.csv").thenReturn(null);
    PowerMockito.whenNew(BufferedReader.class).withArguments(null).thenReturn(reader);
    resultObject=collectionObject.getCollectionObjectAfterWritingFromAFile( "test10.csv");
    assertEquals(expectedObject ,resultObject );
}

答案 2 :(得分:1)

您可以使用JUnit的TemporaryFolder创建文件,并将资源中的内容复制到该文件中。

public YourText {
  @Rule
  public TemporaryFolder folder = new TemporaryFolder();

  @Test
  public void checkSomething() throws Exception {
    InputStream resource = getClass().getResourceAsStream("/your/resource");
    File file = folder.newFile();
    Files.copy(resource, file);
    ReaderFileWriterObjectService service = ...
    CollectionObject collection = service
        .getCollectionObjectAfterWritingFromAFile(file);
    ...
  }

答案 3 :(得分:0)

你做不到。你很幸运。更好的设计会接受Java 7 java.nio.file.FileSystemPath,它们可以换出来进行测试实施,例如: https://github.com/google/jimfs

答案 4 :(得分:0)

好的,首先让我们考虑你想测试什么?如果它是单元测试,那么你不想测试集成,如与文件系统的通信,你必须测试自己的逻辑,你的逻辑是这样的: 1)使用文件系统集成从文件中读取下一行 2)将此行添加到我的对象

第二步你不应该测试,因为这个方法太容易破解。您无法测试的第一步导致它执行集成调用。所以我认为你不需要进行单元测试

但是如果你的逻辑会更复杂,那么你可以在测试中引入界面包装并模拟它:

public interface FileWrapper{
  public String readLine();
  public void close();
}
public class FileWrapperImpl implements FileWrapper{
  private File file;
  private BufferedReader reader;

  public FileWrapperImpl (File file){
     this.file = file;
     this.reader= ...
  }

  public String readLine(){
    return reader.nextLine();
  }
}

然后是您的ReaderFileWriterObjectService:

 public CollectionObject getCollectionObjectAfterWritingFromAFile(FileWrapper wrapper)
        CollectionObject  collectionObject = new CollectionObject();
        while ((line = wrapper.readLine()) != null) {
            collectionObject.add(line);
        }
        wrapper.close();
        return collectionObject;
    }

现在您可以轻松地模拟FileWrapper进行测试并将其传递给您的服务

答案 5 :(得分:0)

我建议更改API以接受Reader或BufferedReader - 这些可以被模拟。使用工厂隐藏文件的依赖关系。