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

时间:2018-11-05 15:26:49

标签: java unit-testing testing junit mockito

提前道歉-我知道这已经被问了一千遍了,但是我浏览了这么多文章/文档,我真是太丢脸了。

我有一个可以接收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 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

您尝试做的实际上不是该方法。您应该仅测试const algoliasearch = require('algoliasearch'); const dotenv = require('dotenv'); const firebase = require('firebase'); // load values from the .env file in this directory into process.env dotenv.load(); // configure firebase firebase.initializeApp({ databaseURL: process.env.FIREBASE_DATABASE_URL, }); const database = firebase.database(); // configure algolia const algolia = algoliasearch( process.env.ALGOLIA_APP_ID, process.env.ALGOLIA_API_KEY ); const index = algolia.initIndex(process.env.ALGOLIA_INDEX_NAME); // Get all contacts from Firebase database.ref('/contacts').once('value', contacts => { // Build an array of all records to push to Algolia const records = []; contacts.forEach(contact => { // get the key and data from the snapshot const childKey = contact.key; const childData = contact.val(); // We set the Algolia objectID as the Firebase .key childData.objectID = childKey; // Add object for indexing records.push(childData); }); // Add or update new objects index .saveObjects(records) .then(() => { console.log('Contacts imported into Algolia'); }) .catch(error => { console.error('Error when importing contact into Algolia', error); process.exit(1); }); }); 类,而不应该测试该类使用的类(XmlToCsvDocumentBuilderFactoryDocumentBuilderDocument,{{1} },StreamSourceTransformer)。

现在有两种选择:干净的代码方式或肮脏的测试方式。

最好的解决方案是为所使用的类提供一个依赖框架:

Source

现在可以通过将模拟注入到可注入字段中来完成测试:

Result

肮脏的方法是使用PowerMockito。使用PowerMockito,您可以覆盖现有类的新方法。这确实是不得已的办法,我不建议这样做,但是当您无法更改源代码时就可以使用它。看起来像这样:

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);

    }
}

您看到的示例还不完整,但是您有所不同。

答案 2 :(得分:0)

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

  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");
      }
    
        ...
    }
    
  3. 一旦您掌握了该技术,就可以通过添加其他XSL以及自己的测试用例来增加测试的复杂性。

别忘了将文件集作为资源添加到您的项目中,成为源代码管理系统的一部分。

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