测试从文件中读取和处理数据的方法

时间:2016-12-29 12:18:13

标签: java unit-testing mockito junit4

我有以下代码:

public class FolderServiceImpl implements FolderService {

    private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);

    public int getStatus(String folderPath) {
        int status = 0;
        File folderStatusFile = new File(folderPath, ".folderstatus");
        if (folderStatusFile.exists()) {
            BufferedReader br = null;
            try {
                br = new BufferedReader(new FileReader(folderStatusFile));
                String line = br.readLine();
                status = Integer.parseInt(line);
            } catch (Exception e) {
                L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
                status = 4;
            } finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        L.warn("could not close reader ", e);
                    }
                }
            }

        } else {
            status = 3;
        }
        return status;
    }
}

我想测试此方法而不为每种情况创建实际文件。我应该使用Java 1.7,JUnit 4,Mockito和/或PowerMockito。

关于如何做到这一点的任何想法?

我说的是模拟数据源或只是改变方法的输入。

我的测试看起来像这样:

`@rule     public TemporaryFolder folder = new TemporaryFolder();

private FolderServiceImpl serviceToTest = new FolderServiceImpl();

private String folderPath;

@Before
public void setUp() {
    folderPath = folder.getRoot().getAbsolutePath();
    try {
        folder.newFile(".folderstatus");
    } catch (IOException e) {
        e.printStackTrace();
    }

}

@Test
public void shouldReturnFolderStatus3WhenFolderStatusIsNotFound() {
    // given
    deleteFolderStatusFile();

    // actual
    int status = serviceToTest.getFolderStatus(folderPath);

    // expected
    assertEquals(3, status);
}

@Test
public void shouldReturnFolderStatus4WhenTheStatusIsUnreadable() {
    // given
    writeStatusToTestFile("Test");

    // actual
    int status = serviceToTest.getFolderStatus(folderPath);

    // expected
    assertEquals(4, status);
}

@Test
public void shouldReturnFolderStatusInTheFile() {
    // given
    writeStatusToTestFile("1");

    // actual
    int status = serviceToTest.getFolderStatus(folderPath);

    // expected
    assertEquals(1, status);

}

private void writeStatusToTestFile(String status) {
    Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
    try {
        Files.write(file, status.getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void deleteFolderStatusFile() {
    Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
    try {
        Files.delete(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
}`

2 个答案:

答案 0 :(得分:0)

你必须使用这样的东西:

var editUser = Session.getEffectiveUser().getEmail()
if (editUser == 'myEmail@gmail.com`)
  return 1;

Powermock将模拟在您的类的getStatus方法中创建的File对象。使用Mockito.when可以说出代码中folderStatusFile.exists()的返回值是什么。

修改

我在maven中加入了以下两个罐子,但您不需要使用maven:https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4/1.4.6https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito/1.4.9以及https://mvnrepository.com/artifact/org.mockito/mockito-all/1.10.19

答案 1 :(得分:0)

虽然@BenHeid的答案可行,但我建议改用不同的方法。

恕我直言,当我使用PowerMock(-ito)时,它是对糟糕设计的投降。 此外,PowerMock解决方案会混淆测试覆盖率工具,因为它在对覆盖率测量进行检测后更改了应用程序字节代码。

所以我更喜欢的方法是坚持清洁代码和OOP规则。

其中一个是关注点分离

在您的情况下,该方法会创建一些要使用的基础结构类(依赖项),即FileReaderBufferedReader

但是(直接)依赖项的实例化不是包含业务逻辑的类的责任。

因此我建议将该代码重构为一个单独的类:

class ReaderFactory {
    public BufferedReader createFor(File file) throws FileNotFoundException {
        return new BufferedReader(new FileReader(file));
    }
}

你的班级将改为:

class FolderServiceImpl {
    private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
    private final ReaderFactory readerFactory;

    FolderServiceImpl(ReaderFactory readerFactory) {
        this.readerFactory = readerFactory;
    }

    public int getStatus(String folderPath) {
        int status = 0;
        File folderStatusFile = new File(folderPath, ".folderstatus");
        // try "with resource" takes care of closing the reader
        try (BufferedReader br = readerFactory.createFor(folderStatusFile);) {
            String line = br.readLine();
            status = Integer.parseInt(line);
        } catch (IOException e) {
            status = 3;
        } catch (Exception e) {
            L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
            status = 4;
        }
        return status;
    }
}

你的测试就是这样:

public class FolderServiceImplTest {

    private static final String ANY_FILE_NAME = "";

    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Mock
    private ReaderFactory readerFactory;

    @InjectMocks
    FolderServiceImpl sut;

    @Test
    public void getStatus_FileNotExisting_returnStatus3() throws Exception {
        // arrange
        Mockito.doThrow(new FileNotFoundException("UnitTest")).when(readerFactory).createFor(Mockito.any(File.class));
        // act
        int status = sut.getStatus(ANY_FILE_NAME);
        // assert
        Assert.assertThat("status",status,CoreMatchers.equalTo(3));
    }

    @Test
    public void getStatus_ValidFile_returnFileContentAsInt() throws Exception {
        // arrange
        BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
        Mockito.doReturn(bufferedReader).when(readerFactory).createFor(Mockito.any(File.class));
        Mockito.doReturn("4711").when(bufferedReader).readLine();
        // act
        int status = sut.getStatus(ANY_FILE_NAME);
        // assert
        Assert.assertThat("status",status,CoreMatchers.equalTo(4711));
    }
}