Mockito返回FileNotFoundException,尽管文件在那里

时间:2016-10-10 09:29:58

标签: java spring-boot mockito

我试图在新的Spring Boot创建的服务类上运行测试。 StringWriter内容是常规XML,带有几行名为' transaction'的标记。

PrepareExcelServiceTest 的.class

@SpringBootTest
@RunWith(MockitoJUnitRunner.class)
public class PrepareExcelServiceTest {

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

    private static final Logger log = LoggerFactory.getLogger(PrepareExcelService.class);

    @Test
    public void testPrepareExcelService() throws ParserConfigurationException, SAXException, IOException {
        PrepareExcelService prepareExcelService = new PrepareExcelService();
        StringWriter xmlStringWriter = new StringWriter();

        Source source = new StreamSource("./view/xml/0_dummy.xml");
        xmlStringWriter.write(source.toString());

        prepareExcelService.prepareDocument(xmlStringWriter);
    }
}

PrepareExcelService 的.class

@Service
public class PrepareExcelService {

    private HSSFWorkbook workbook;
    private HSSFSheet spreadsheet;

    public void prepareDocument(StringWriter xmlStringWriter) throws IOException,
                                                                            SAXException, ParserConfigurationException {
        workbook = setupWorkBook();
        spreadsheet = setupSheet(workbook);

        Document document = parseXMLStringWriter(xmlStringWriter);
        fillContent(document, spreadsheet);

        FileOutputStream output = new FileOutputStream(new File("TestExcelFile.xls"));
        workbook.write(output);
        output.flush();
        output.close();
    }

    private HSSFWorkbook setupWorkBook() {
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFCellStyle cellStyle = workbook.createCellStyle();

        cellStyle.setBorderLeft(BorderStyle.MEDIUM);
        cellStyle.setBorderRight(BorderStyle.MEDIUM);
        cellStyle.setBorderTop(BorderStyle.MEDIUM);
        cellStyle.setBorderBottom(BorderStyle.MEDIUM);
        cellStyle.setIndention((short)4);
        cellStyle.setWrapText(true);

        HSSFFont font = workbook.createFont();
        font.setFontHeightInPoints((short)24);
        font.setFontName("Courier New");
        font.setItalic(false);
        cellStyle.setFont(font);

        return workbook;
    }

    private HSSFSheet setupSheet(HSSFWorkbook workbook) {
        HSSFSheet spreadSheet = workbook.createSheet("spreadSheet");
        return spreadSheet;
    }

    private Document parseXMLStringWriter(StringWriter xmlStringWriter) throws ParserConfigurationException,
                                                                                            IOException, SAXException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();

        return builder.parse(xmlStringWriter.toString());
    }

    private void fillContent (Document document, HSSFSheet spreadSheet) {
        HSSFRow row = spreadSheet.createRow(0);
        HSSFCell cell = row.createCell((short) 1);

        NodeList nodeList = document.getElementsByTagName("transaction");
        HSSFRow rowOne = spreadSheet.createRow(1);

        cell.setCellValue("Spreadsheet Header Row");

        for (int i = 0; i < nodeList.getLength(); i++) {
            switch (i) {
                case 0:
                    cell = rowOne.createCell((short) 0);
                    cell.setCellValue("transaction");
                    cell = rowOne.createCell((short) 1);
                    cell.setCellValue(((Element) (nodeList.item(0))).getElementsByTagName("transaction").item(0)
                                                                                        .getFirstChild().getNodeValue());
                    break;
                default:
                    break;
            }
        }
    }
}

在测试此服务时,我得到以下异常,尽管该文件存在,而其他服务通过StringWriter正确地与它进行交互。

java.io.FileNotFoundException: ...\javax.xml.transform.stream.StreamSource@4439f31e (The system cannot find the file specified)

    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:90)
    at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:188)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:623)
    at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:189)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:812)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
    at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
    at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:177)
    at ee.estcard.repgen.service.PrepareExcelService.parseXMLStringWriter(PrepareExcelService.java:78)
    at ee.estcard.repgen.service.PrepareExcelService.prepareDocument(PrepareExcelService.java:39)
    at ee.estcard.repgen.service.PrepareExcelServiceTest.testPrepareExcelService(PrepareExcelServiceTest.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.mockito.internal.junit.JUnitRule$1.evaluate(JUnitRule.java:16)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

我认为问题在于我对StringWriter的错误使用,但由于我对Java的新手知识,我仍然无法解决这个问题。

2 个答案:

答案 0 :(得分:2)

没有问题与您使用StreamSource的方式有关,确实调用source.toString()不会像您期望的那样向您提供来源的内容,但是javax.xml.transform.stream.StreamSource@4439f31e就像您一样可以在你的堆栈跟踪中看到。

只需删除您的StringWriter并在代码中使用InputSource来修复代码,同时也可以使其更灵活,因为使用InputSource可以打开许多不同的代码类型的源,而且加载文件的内容不是一个好的做法,应该避免,因为如果文件太大,你可能会面对OOME,如果它不适合堆。

PrepareExcelServiceTest

PrepareExcelService prepareExcelService = new PrepareExcelService();
InputSource source = new InputSource("./view/xml/0_dummy.xml");
prepareExcelService.prepareDocument(source);

在要重命名的方法parseXMLStringWriter

private Document parseXML(InputSource source) throws ParserConfigurationException,
    IOException, SAXException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();

    return builder.parse(source);
}

方法prepareDocument

public void prepareDocument(InputSource source) throws IOException,
    SAXException, ParserConfigurationException {
    ...

    Document document = parseXML(source);

    ...
}

答案 1 :(得分:1)

首先,我怀疑StringWriter是用于传输“字符串内容”的方法签名的好类型。有许多替代方案,使用指针(即URI,路径,文件)到内容或角色内容的一些消费表示(Reader,InputStream,InputSourc)或内容本身(String)。

但是假设你是故意这样做的:

DocumentBuilder的{​​{1}}方法接受:

  • parse()
  • InputSource
  • 指向文件的URI字符串

你的StringWriter或更好,它的InputStream方法的结果都不是它们。因此,您需要将toString()的缓冲区内容转换为任何类型的内容。

最简单的可能就是

StringWriter

所以方法可能如下:

new InputSource(new StringReader(xmlStringWriter.toString()))

现在,您可以解析编写器中包含的字符串。但是,内容仍然是错误的。

private Document parseXMLStringWriter(StringWriter xmlStringWriter) throws ParserConfigurationException, IOException, SAXException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); return builder.parse(new InputSource(new StringReader(xmlStringWriter.toString()))); } 的{​​{1}}方法创建了一个对象引用字符串,但不生成StreamSource引用的文件的内容。相反,您需要获取文件的内容。

将文件内容转换为String的最简单方法可能是

StreamSource

(忽略文件的编码)

这应该让你的测试运行。但同样,请不要使用StringWriter。