如何测试这个文件写入,3lines 功能?

Kon*_*rdź 2 java testing unit-testing mockito writer

这是我在某个服务类中的方法。它是公开的,因此应该进行测试。我只是不知道我应该测试什么。我会模拟Writer和 spyOn 函数调用,但是使用这种实现是不可能的(不是吗?)

我正在使用Mockito和JUnit

现在,我只能使函数抛出和断言该异常

有什么帮助吗?

@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()
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

Tim*_*kle 5

如果您觉得添加特殊内容是业务逻辑,因此是您的类的责任,那么创建 FileWriter 就不是(根据单一责任模式.

因此,您应该使用在 Test 下FileWriterFactory注入到您的Class 中的。然后你可以模拟它FileWriterFactory以返回Writer接口的模拟实现,然后你可以检查它是否获得了预期的字符串。

您的 CuT 将更改为:

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()
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

以及您对此的测试:

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

此外,您可以轻松检查您的 CuT 是否拦截了 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);
  }
Run Code Online (Sandbox Code Playgroud)

好的!一个工厂只是为了测试 3 行代码!– 尼古拉斯·菲洛托

这是个好的观点。

问题是:该类中是否有任何方法File直接与对象交互并需要在之后创建 FileWriter?

如果遵循 KISS 原则的答案是“否”(因为它最有可能),您应该Writer直接注入一个对象而不是工厂,并且您的方法没有 File 参数。

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()
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

修改测试:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)