抽象类Java中的模拟异常

抽象类Java中的模拟异常,java,junit,mocking,mockito,Java,Junit,Mocking,Mockito,我需要用Junit测试抽象类中的一些异常 抽象类: public abstract class AbstractReport { private final Log logger = LogFactory.getLog(this.getClass()); private static final String PREFIX_NAME = "reportFile"; protected Path generate(String templatePath, Map<

我需要用Junit测试抽象类中的一些异常

抽象类:

public abstract class AbstractReport {

    private final Log logger = LogFactory.getLog(this.getClass());

    private static final String PREFIX_NAME = "reportFile";

    protected Path generate(String templatePath, Map<String, Object> params, JRDataSource datasource) {
        // Temporal file to write the document
        Path file = null;
        try {
            file = Files.createTempFile(PREFIX_NAME, null);
        } catch (final IOException e) {
            logger.error("Exception creating temp file",e);
            return null;
        }

        try (InputStream reportStream = this.getClass().getResourceAsStream(templatePath); FileOutputStream outputStream = new FileOutputStream(file.toFile())) {
            final JasperDesign jd = JRXmlLoader.load(reportStream);
            final JasperReport jr = JasperCompileManager.compileReport(jd);
            final JasperPrint jp = JasperFillManager.fillReport(jr, params, datasource);

            final JRPdfExporter exporter = new JRPdfExporter();
            exporter.setExporterInput(SimpleExporterInput.getInstance(Arrays.asList(jp)));

            final SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
            exporter.setConfiguration(configuration);
            exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));
            exporter.exportReport();
        } catch (final JRException e) {
            logger.error("Exception processing report",e);
            file.toFile().delete();
            return null;
        } catch (final FileNotFoundException e) {
            logger.error("Report template not found",e);
            file.toFile().delete();
            return null;
        } catch (final IOException e) {
            logger.error("Exception reading report template",e);
            file.toFile().delete();
            return null;
        }

        return file;
    }
}

我需要测试这段代码中的每个捕获。通过研究,我发现使用Mockito可以在调用方法时模拟异常,例如,我可以在调用generate时触发异常,我不知道如何在生成代码中引发异常,例如在创建临时文件时引发IOException。

我想在您的情况下,异常是由静态方法调用引发的。Mockito无法模拟静态方法调用,因为它被认为是糟糕的设计。 如果您不想重构代码,可以使用PowerMockito

这将使方法JRXmlLoader.load引发IOException。同样,您可以模拟静态方法来抛出其他异常

有关更多详细信息,请参阅

如果您不想添加额外的依赖项,那么我建议封装静态方法的调用:

class JaspreUtilsProvider {

    JasperDesign loadJasperDesign(InputStream reportStream) throws ... {
        JRXmlLoader.load(reportStream);
    }

    //encapsulating other static methods
}
然后将该类作为依赖项传递给AbstractReport构造函数。现在将静态方法的所有调用更改为此对象的调用

public abstract class AbstractReport {
    private final JaspreUtilsProvider jaspreUtilsProvider;

    public AbstractReport(JaspreUtilsProvider jaspreUtilsProvider) {
        this.jaspreUtilsProvider = jaspreUtilsProvider;
    }

    protected Path generate(String templatePath, Map<String, Object> params, JRDataSource datasource) {
        //.........
         final JasperDesign jd = jaspreUtilsProvider.loadJasperDesign(reportStream); // instead of JRXmlLoader.load(reportStream);
        //.........
    }
}

现在很容易创建JaspreUtilsProvider的子类,该子类抛出异常并将其传递给测试类,而不是真正的JaspreUtilsProvider实例。这是最便宜的解决方案。

如果这个类没有依赖项,就没有什么可模仿的了。谢谢Serghey。现在我无法为我的项目添加额外的库,所以我想我必须找到另一个解决方案。无论如何,为了理解它,在你说调用测试类的方法的部分,如果我调用从MyReport生成的方法,它扩展了AbstractReport,一旦它到达JRXmlLoader.load,它就会触发异常?MyReport是如何注入JRXmlLoader mock的?是的,只要调用了JRXmlLoader.load,即使调用发生在抽象类中,PowerMock也可以为您模拟调用。如果现在需要添加额外的依赖项,然后,您应该将静态方法的调用封装到另一个对象中,该对象将为您执行此调用。然后将此对象作为依赖项传递给类。
public abstract class AbstractReport {
    private final JaspreUtilsProvider jaspreUtilsProvider;

    public AbstractReport(JaspreUtilsProvider jaspreUtilsProvider) {
        this.jaspreUtilsProvider = jaspreUtilsProvider;
    }

    protected Path generate(String templatePath, Map<String, Object> params, JRDataSource datasource) {
        //.........
         final JasperDesign jd = jaspreUtilsProvider.loadJasperDesign(reportStream); // instead of JRXmlLoader.load(reportStream);
        //.........
    }
}