如何测试外部class执行的IO?
How to test IO performed by external class?
我有一个简单的 class 可以将数据写入 CSV 文件:
public class CsvFileWriter {
private static Logger logger = LogManager.getLogger();
public static void writeDataToCsvFile(String filePath, List<String[]> data) {
File file = new File(filePath);
try (FileWriter outputFile = new FileWriter(file)) {
CSVWriter writer = new CSVWriter(outputFile, ' ',
CSVWriter.NO_QUOTE_CHARACTER,
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END);
writer.writeAll(data);
} catch (IOException e) {
logger.error("Unable to find the specified path", e);
throw new ProjectException(e);
}
}
}
我想知道如何测试这个class中包含的方法。我发现可以使用 Mockito 完成此操作的信息。是这样吗?我该怎么做?
您不需要 Mockito 或任何模拟来测试它(故障处理和日志记录除外)。
您应该使用 Junit 5 中的 @TempDir
,或 Junit 4 中的 TemporaryFolder
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
class CsvFileWriterTest {
@Test
void createsCsvFile(@TempDir final Path temp) {
final var csv = temp.resolve("test.csv");
CsvFileWriter.writeDataToCsvFile(
csv.toString(),
List.of(
new String[]{"1", "abc"},
new String[]{"2", "def"}
)
);
Assertions.assertTrue(csv.toFile().exists());
}
@Test
void writesDataToCsv(@TempDir final Path temp) throws IOException {
final var csv = temp.resolve("test.csv");
CsvFileWriter.writeDataToCsvFile(
csv.toString(),
List.of(
new String[]{"1", "abc"},
new String[]{"2", "def"}
)
);
Assertions.assertEquals(
Files.readAllLines(csv),
List.of("1 abc", "2 def")
);
}
}
虽然您可能想要重构您的 class 以便更易于测试:
@lombok.RequiredArgsConstructor
public class CsvFileWriter {
private static final Logger LOG = LogManager.getLogger();
private final Path file;
private final Function<Writer, CSVWriter> csvfactory;
public CsvFileWriter(final Path file) {
this(
file,
writer ->
new CSVWriter(writer, ' ',
CSVWriter.NO_QUOTE_CHARACTER,
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END
)
);
}
public void write(final List<String[]> data) {
try (var csv = this.csvfactory.apply(Files.newBufferedWriter(this.file))) {
csv.writeAll(data);
} catch (IOException ex) {
LOG.error("Unable to find the specified path", ex);
throw new UncheckedIOException(ex);
}
}
}
现在您可以将工厂方法传递给构造函数,并使用它来模拟 CSVWriter
。例如,您可以测试您是否正确处理了 IOException class:
@Test
void handlesIoException(@TempDir final Path temp) {
final var mock = Mockito.mock(CSVWriter.class);
Mockito.doThrow(IOException.class).when(mock).writeAll(Mockito.anyList());
final var writer = new CsvFileWriter(temp.resolve("not.csv"), wrt -> mock);
Assertions.assertThrows(
UncheckedIOException.class,
() -> writer.write(List.of())
);
}
我有一个简单的 class 可以将数据写入 CSV 文件:
public class CsvFileWriter {
private static Logger logger = LogManager.getLogger();
public static void writeDataToCsvFile(String filePath, List<String[]> data) {
File file = new File(filePath);
try (FileWriter outputFile = new FileWriter(file)) {
CSVWriter writer = new CSVWriter(outputFile, ' ',
CSVWriter.NO_QUOTE_CHARACTER,
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END);
writer.writeAll(data);
} catch (IOException e) {
logger.error("Unable to find the specified path", e);
throw new ProjectException(e);
}
}
}
我想知道如何测试这个class中包含的方法。我发现可以使用 Mockito 完成此操作的信息。是这样吗?我该怎么做?
您不需要 Mockito 或任何模拟来测试它(故障处理和日志记录除外)。
您应该使用 Junit 5 中的 @TempDir
,或 Junit 4 中的 TemporaryFolder
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
class CsvFileWriterTest {
@Test
void createsCsvFile(@TempDir final Path temp) {
final var csv = temp.resolve("test.csv");
CsvFileWriter.writeDataToCsvFile(
csv.toString(),
List.of(
new String[]{"1", "abc"},
new String[]{"2", "def"}
)
);
Assertions.assertTrue(csv.toFile().exists());
}
@Test
void writesDataToCsv(@TempDir final Path temp) throws IOException {
final var csv = temp.resolve("test.csv");
CsvFileWriter.writeDataToCsvFile(
csv.toString(),
List.of(
new String[]{"1", "abc"},
new String[]{"2", "def"}
)
);
Assertions.assertEquals(
Files.readAllLines(csv),
List.of("1 abc", "2 def")
);
}
}
虽然您可能想要重构您的 class 以便更易于测试:
@lombok.RequiredArgsConstructor
public class CsvFileWriter {
private static final Logger LOG = LogManager.getLogger();
private final Path file;
private final Function<Writer, CSVWriter> csvfactory;
public CsvFileWriter(final Path file) {
this(
file,
writer ->
new CSVWriter(writer, ' ',
CSVWriter.NO_QUOTE_CHARACTER,
CSVWriter.DEFAULT_ESCAPE_CHARACTER,
CSVWriter.DEFAULT_LINE_END
)
);
}
public void write(final List<String[]> data) {
try (var csv = this.csvfactory.apply(Files.newBufferedWriter(this.file))) {
csv.writeAll(data);
} catch (IOException ex) {
LOG.error("Unable to find the specified path", ex);
throw new UncheckedIOException(ex);
}
}
}
现在您可以将工厂方法传递给构造函数,并使用它来模拟 CSVWriter
。例如,您可以测试您是否正确处理了 IOException class:
@Test
void handlesIoException(@TempDir final Path temp) {
final var mock = Mockito.mock(CSVWriter.class);
Mockito.doThrow(IOException.class).when(mock).writeAll(Mockito.anyList());
final var writer = new CsvFileWriter(temp.resolve("not.csv"), wrt -> mock);
Assertions.assertThrows(
UncheckedIOException.class,
() -> writer.write(List.of())
);
}