我一直在尝试编写一个单元测试,试图在我的课堂上完全覆盖。
我正在尝试测试它是否正确捕获了DOMUtil类中此方法抛出的 TransformerException :
public final class DOMUtil
{
// This class is entirely static, so there's no need to ever create an instance.
private DOMUtil()
{
// Do nothing.
}
...
...
/**
* Returns a String containing XML corresponding to a Document. The String
* consists of lines, indented to match the Document structure.
* @param doc - Document to be converted.
* @return String containing XML or null if an error occurs.
*/
public static String documentToString(final Document doc)
{
try
{
// Note that there is no control over many aspects of the conversion,
// e.g., insignificant whitespace, types of quotes.
final Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
tf.setOutputProperty(OutputKeys.INDENT, "yes");
final Writer out = new StringWriter();
tf.transform(new DOMSource(doc), new StreamResult(out));
return out.toString();
}
catch (final TransformerException e)
{
LOG.error("Error converting Document to String: " + e.getMessage());
return null;
}
}
}
我的DOMUtilTest类:
@RunWith(PowerMockRunner.class)
...
...
@PrepareForTest({Document.class, TransformerFactory.class, Transformer.class, DOMUtil.class, DocumentBuilder.class, DocumentBuilderFactory.class})
public class DOMUtilTest
{
/**
* Test documentToString with TransformerException
*/
@Test(expected=TransformerException.class)
public void testDocumentToStringTransformerException()
{
try
{
// Mocking Stuff
TransformerFactory fac = PowerMockito.mock(TransformerFactory.class);
Transformer transformer = PowerMockito.mock(Transformer.class);
// probably only need two of these??
PowerMockito.whenNew(TransformerFactory.class).withNoArguments().thenReturn(fac);
PowerMockito.whenNew(Transformer.class).withNoArguments().thenReturn(transformer);
PowerMockito.when(fac.newTransformer(ArgumentMatchers.any(Source.class))).thenReturn(transformer);
PowerMockito.when(fac.newTransformer()).thenReturn(transformer);
// spy in results
PowerMockito.spy(transformer);
PowerMockito.when(transformer, "transform", ArgumentMatchers.any(Source.class), ArgumentMatchers.any(Result.class)).thenThrow(new TransformerException("Mocked TransformerException"));
final String result = DOMUtil.documentToString(doc);
LOG.info("result length: " + result.length());
}
catch(Exception e)
{
LOG.error("Exception in testDocumentToStringTransformerException: " + e.getMessage());
fail("Exception in testDocumentToStringTransformerException: " + e.getMessage());
}
}
}
我觉得我已经尝试了所有可能的解决方案。我在其他类/方法上有很多类似条件的工作测试。我试过了
以及我能想到的其他所有方式。现在结果仍然显示:结果长度:25706(doc对象的实际长度),在复制文档之前没有出现异常。
以下是Java 7 API - Exceptions and Error Reporting对 TransformationException 的进一步说明。
TransformerException是一个常见的异常,发生在 转型的过程。变压器异常可以包装另一个 异常,如果有任何TransformerException.printStackTrace() 在它上面调用方法,它会产生一个堆栈转储列表, 从最近开始。变压器例外也提供 一个SourceLocator对象,它指示源树中的位置或 转换指令发生错误。 可以调用TransformerException.getMessageAndLocation()来获取 带位置信息的错误消息,和 可以调用TransformerException.getLocationAsString()来获取 位置字符串。
我的假设是问题在于嘲笑这条线:
final Transformer tf = TransformerFactory.newInstance().newTransformer();
有没有人遇到过这样的情况,有JUnit和PowerMockito?
如果有人能指出我正确的方向或告诉我如何解决这个问题,我们将不胜感激。
谢谢!
答案 0 :(得分:0)
从理论上讲,这似乎不是模仿 TransformerException 最漂亮的方式,但经过大量的研究和尝试,我想出了嘲笑结果 tf.transform 的outputTarget参数:
@Test
public void testDocumentToStringTransformerException() throws Exception
{
// Mocking Stuff
PowerMockito.whenNew(StringWriter.class).withNoArguments().thenReturn(null);
// Execute Method Under Test
final String result = DOMUtil.documentToString(doc);
// Verify Result
assertNull(result);
}
最终会给出:
XML-22122: (Fatal Error) Invalid StreamResult - OutputStream, Writer, and SystemId are null.
封装成TransformerException。这允许我测试代码覆盖的TransformerException分支。
所以好消息是它可以通过模拟,而不是试图弄清楚如何操纵Document对象来抛出异常。也不必像我最初想的那样模拟尽可能多的对象。
(这里引用TransformerException:Java 7 API - Exceptions and Error Reporting)