2017-04-11 82 views
0

我需要使用Junit抽象类中的一些异常进行测试。抽象类Java中的模拟异常

抽象类:

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

+1

如果这个类没有依赖关系,那就没有什么可以模拟的。 –

回答

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例如您的测试类。这是最便宜的解决方案。

+0

谢谢Serghey。现在我无法将额外的库添加到我的项目中,所以我想我将不得不寻找其他解决方案。无论如何,为了理解它,在你称之为“调用你的测试类的方法”的部分,如果我从MyReport调用了方法'generate',它扩展了AbstractReport,一旦它达到'JRXmlLoader.load',它就会引发异常? MyReport如何获得“JRXmlLoader”(模拟)注入? – maqjav

+0

是的,只要你调用了'JRXmlLoader .load',即使这个调用发生在你的抽象类中'PowerMock'能够为你调用这个调用。 –

+0

如果您现在添加额外的依赖关系,那么您应该在另一个对象中封装对静态方法的调用,以便为您调用此调用。然后将此对象作为依赖项传递给您的类。 –