为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

叮当猫咪 2021-12-30 20:26:43
提前道歉 - 我知道这已经被问了一千次了,但我已经浏览了很多文章/文档,我真的很迷茫。我有一个类,它接收一个 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);    }}
查看完整描述

3 回答

?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

你试图做的实际上不是这样做的方式。您应该只测试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 verify


verify(documentBuilder, times(1)).parse(any(File.class));

    }

}

如您所见,示例并不完整,但您会发现不同之处。


查看完整回答
反对 回复 2021-12-30
?
芜湖不芜

TA贡献1796条经验 获得超7个赞

要测试代码生成器,这是我发现的最佳方法:

  1. 准备一组具有相同 XSL的测试用例:对于每个测试用例,一个 XML 输入文件和一个预期的 CSV 输出文件。将输入文件放入一个目录,将预期的文件放入另一个目录,但为每对文件(case1.xmlcase1.csv)设置相同的名称。

  2. 使用应该进行测试和比较的私有方法编写 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 及其自己的测试用例来增加测试的复杂性。


不要忘记将文件集作为资源添加到您的项目中,以成为源代码控制系统的一部分。


注意:此方法假定每个输出文件仅取决于输入文件的内容。如果生成器添加了一些独立的内容(如当前日期、当前用户等),则必须进行先前的预处理。


查看完整回答
反对 回复 2021-12-30
?
温温酱

TA贡献1752条经验 获得超4个赞

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


查看完整回答
反对 回复 2021-12-30
  • 3 回答
  • 0 关注
  • 307 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信