猿问

如何使用 JUnit 和/或 Mockito 测试 void 方法

提前道歉 - 我知道这已经被问了一千次了,但我已经浏览了很多文章/文档,我真的很迷茫。


我有一个类,它接收一个 XML 文件,然后使用 DocumentBuilder 将其解析为一个新文件,该文件将用作其他类使用的源。


我需要测试我的方法(无效)。我的项目已经完成,但我需要测试。


如果有人能向我展示这将如何完成,我可以继续对我的其他类遵循相同的逻辑,因为我项目中 90% 的方法不返回任何内容。


谢谢...


 public class XmlToCsv {



    public static void xmlToCsv(String sourceXlsFile, String sourceCsvFile, String sourceXmlFile) throws Exception {


        //define the files

        File stylesheet = new File(sourceXlsFile);

        File xmlSource = new File(sourceXmlFile);


        //create the DocumentBuilder to parse the XML file

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        DocumentBuilder builder = factory.newDocumentBuilder();

        Document document = builder.parse(xmlSource);


        //input the stylesheet to transform the XML to

        StreamSource stylesource = new StreamSource(stylesheet);

        Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);


        //write a new output file using the stylesheet format

        Source source = new DOMSource(document);

        Result outputTarget = new StreamResult(new File(sourceCsvFile));

        transformer.transform(source, outputTarget);


    }

}


叮当猫咪
浏览 308回答 3
3回答

慕桂英3389331

你试图做的实际上不是这样做的方式。您应该只测试XmlToCsv该类,而不是该类使用的类(DocumentBuilderFactory, DocumentBuilder, Document, StreamSource, Transformer, Source, Result)。现在有两种方法可以走:干净的代码方式,或脏测试的方式。最好的解决方案是为您使用的类建立一个依赖框架:public class XmlToCsv {    @Inject    DocumentBuilderFactory factory;    @Inject    StreamSource stylesource;    @Inject    TransformerFactory transformerFactory;    public void xmlToCsv(String sourceXlsFile, String sourceCsvFile, String sourceXmlFile) throws Exception {        //define the files        File stylesheet = new File(sourceXlsFile);        File xmlSource = new File(sourceXmlFile);        //create the DocumentBuilder to parse the XML file        DocumentBuilder builder = factory.newDocumentBuilder();        Document document = builder.parse(xmlSource);        //input the stylesheet to transform the XML to        StreamSource stylesource = new StreamSource(stylesheet);        Transformer transformer = transformerFactory.newInstance().newTransformer(stylesource);        //write a new output file using the stylesheet format        Source source = new DOMSource(document);        Result outputTarget = new StreamResult(new File(sourceCsvFile));        transformer.transform(source, outputTarget);    }}现在可以通过将模拟注入可注入字段来完成测试:@RunWith(MockitoJUnitRunner.class)public class XmlToCsvTest {    @Mock    DocumentBuilderFactory factory;    @Mock    StreamSource style source;    @Mock    TransformerFactory transformerFactory;    @InjectMocks    XmlToCsv sut; // System Under Test    @Test    public void testOk() throws Exception {        // Mocks        DocumentBuilder documentBuilder = Mockito.mock(DocumentBuilder.class);        Document document = Mockito.mock(Document.class);        // Now you control all objects created in the class and you can test if the right methods are called        // when-clauses        Mockito.when(factory.newDocumentBuilder).thenReturn(documentBuilder);        Mockito.when(documentBuilder.parse(any(File.class)).thenReturn(document);        // Add all when's here        // now call the class        sut.xmlToCsv("", "", "");        // now verify all calls        verify(factory, times(1)).newDocumentBuilder();        verify(documentBuilder, times(1)).parse(any(File.class));        // etc.    }}肮脏的方法是使用 PowerMockito。使用 PowerMockito,您可以覆盖现有类的新方法。这确实是最后的手段,我不推荐它,但是当您无法更改源代码时可以使用它。它看起来像这样:@RunWith(PowerMockRunner.class)@PrepareForTest({XmlToCsv.class, DocumentBuilderFactory.class})public class XmlToCsvTest {    XmlToCsv sut;    @Test    public void testXmlToCsv() throws Exception {        DocumentBuilder documentBuilder = Mockito.mock(DocumentBuilder.class);        Document document = Mockito.mock(Document.class);        //when phase        PowerMockito.mockStatic(DocumentBuilderFactory.newInstance).thenReturn(documentBuilder);        Mockito.when(factory.newDocumentBuilder).thenReturn(documentBuilder);        Mockito.when(documentBuilder.parse(any(File.class)).thenReturn(document);        // now call the class        sut.xmlToCsv("", "", "");        //now verifyverify(documentBuilder, times(1)).parse(any(File.class));    }}如您所见,示例并不完整,但您会发现不同之处。

芜湖不芜

要测试代码生成器,这是我发现的最佳方法:准备一组具有相同 XSL的测试用例:对于每个测试用例,一个 XML 输入文件和一个预期的 CSV 输出文件。将输入文件放入一个目录,将预期的文件放入另一个目录,但为每对文件(case1.xml和case1.csv)设置相同的名称。使用应该进行测试和比较的私有方法编写 JUnit 类,然后@Test为每个要测试的案例添加一个方法:import java.io.File;import org.apache.commons.io.FileUtils;public class XmlToCsvTest{  private final File inputDir=new File("my_input_xml_files");  private final File expectedDir=new File("my_expected_csv_files");  private final File generatedDir=new File("my_generated_files"); // This is just a working dir  private void xmlToCsv(String xslFile, String inputFileName)  {    try    {      File inputXmlFile=new File(this.inputDir, inputFileName + ".xml");      File outputCsvFile=new File(this.generatedDir, inputFileName + ".csv");      File expectedCsvFile=new File(this.expectedDir, inputFileName + ".csv");      xmlToCsv(xslFile, outputCsvFile.getAbsolutePath(), inputXmlFile.getAbsolutePath());      FileUtils.contentEquals(expectedCsvFile, outputCsvFile);    }    catch (Exception e)    {      fail(e.toString());    }  }  @Test  public void xmlToCsvWithCase1()  {    xmlToCsv("myFirst.xsl", "case1");  }  @Test  public void xmlToCsvWithEmptyFile()  {    xmlToCsv("myFirst.xsl", "empty");  }  @Test  public void xmlToCsvWithOneRow()  {    xmlToCsv("myFirst.xsl", "one-row");  }    ...}一旦您掌握了这项技术,您就可以通过添加其他 XSL 及其自己的测试用例来增加测试的复杂性。不要忘记将文件集作为资源添加到您的项目中,以成为源代码控制系统的一部分。注意:此方法假定每个输出文件仅取决于输入文件的内容。如果生成器添加了一些独立的内容(如当前日期、当前用户等),则必须进行先前的预处理。

温温酱

看起来您想要测试此方法的方式是验证写入sourceCsvFile参数的文件的预期内容,您可以通过在调用方法后读取内容来实现。我认为您不需要对 Mockito 做任何事情——您的所有参数都是 String 对象,因此无需创建任何模拟。
随时随地看视频慕课网APP

相关分类

Java
我要回答