抽象类Java中的模拟异常

时间:2017-04-11 08:51:11

标签: 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<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;
    }
}

我需要测试此代码中的每个catch。研究我发现使用 Mockito 你可以在调用方法时模拟异常,所以例如我可以在调用“generate”时触发异常,但是,我不知道如何在内部触发异常我的“生成”代码(例如创建临时文件时的IOException)。

1 个答案:

答案 0 :(得分:1)

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

@PrepareForTest({JRXmlLoader.class})
@RunWith(PowerMockRunner.class)
public class ReportTest {
    @Test
    public void test() {
        PowerMockito.mockStatic(JRXmlLoader.class);
        when(JRXmlLoader.load(any(InputStream.class))).thenThrow(new IOException());
        //call the method of your test class
    }
}

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

您可以参考this docs了解详情。

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

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实例。这是最便宜的解决方案。