mercredi 24 janvier 2018

How do you write a JUnit Test for TransformerException from javax.xml.transform.Transformer.transform

I have been trying to write a unit test in an attempt to reach full coverage on my class under test.

I am trying to test that it properly catches the TransformerException thrown from this method in class DOMUtil:

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

My DOMUtilTest class:

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

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

I feel like I have tried every possible solution. I have a lot of working tests with similar conditions on other classes/methods. I have tried

  • annotations style mocking/injecting
  • spying
  • ArgumentMatchers.any(DOMSource.class), ArgumentMatchers.any(StreamResult.class) (which gives error: The method any(Class) from the type ArgumentMatchers refers to the missing type DOMSource)

and every other possible way I could think of. Right now the result is still showing: result length: 25706 (the real length of the doc object) without getting an exception before copying the document.

My assumption is the problem is with mocking of the line:

final Transformer tf = TransformerFactory.newInstance().newTransformer();

If anybody could point me in the right direction or show me how to solve this any help would be greatly appreciated.

Thanks!

Aucun commentaire:

Enregistrer un commentaire