如何在具有InputStream的方法中捕获JUnit中的IOException。

huangapple go评论76阅读模式
英文:

How to cover IOException from method that has InputStream in JUnit

问题

public String GetstrXMLValue(String strXML, String strCriteria) {
    SAXBuilder builder = new SAXBuilder();
    builder.setProperty(XMLConstants.ACCESS_S1, "");
    builder.setProperty(XMLConstants.ACCESS_S2, "");

    Document xmlDocument;
    String strValue = "";
    ErrorHandler objErrHdl = new ErrorHandler();
    
    try {
        InputStream objStream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));

        xmlDocument = builder.build(objStream);
            
        XPathFactory xpath = XPathFactory.instance(); 
      
        XPathExpression<Object> expr = xpath.compile(strCriteria);
      
        List<Object> xPathSearchedNodes = expr.evaluate(xmlDocument);
        
        if (xPathSearchedNodes.size() > 0) {
        
            Content content = (Content) xPathSearchedNodes.get(0);
            
            strValue = content.getValue().toString();
        }
        
    } catch (JDOMException e) {
        objErrHdl.LogError(this.getClass().getName(), "GetstrXMLValue", "ERROR RETRIEVING XML VALUES (XML=" + strXML + ";CRITERIA=" + strCriteria + ")", e.toString());
    } catch (IOException e) {
        objErrHdl.LogError(this.getClass().getName(), "GetstrXMLValue", "ERROR RETRIEVING XML VALUES (XML=" + strXML + ";CRITERIA=" + strCriteria + ")", e.toString());
    } catch (Exception e) {
        objErrHdl.LogError(this.getClass().getName(), "GetstrXMLValue", "ERROR RETRIEVING XML VALUES (XML=" + strXML + ";CRITERIA=" + strCriteria + ")", e.toString());
    }
            
    return strValue;
}
@Test
public void testGetstrXMLValueThrowsIOException() throws IOException, ParserConfigurationException, SAXException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
    OutputStream responseBody = new ByteArrayOutputStream();
    String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + 
            "                <RESULT>\r\n" + 
            "                <SHORT_NAME>XXXXXXXXXXXXX</SHORT_NAME>\r\n" + 
            "                <ID_CODE>9999999999999</ID_CODE>\r\n" + 
            "                </RESULT>";
    
    xmlHandler.XMLGenerateRootResult();
    xmlHandler.GetstrXMLValue(xml, ".//RESULT/ID_CODE/text()");
    try
    {
        InputStream input = XMLHandlerTest.readXML(xml);
        byte[] buffer = new byte[1024];
        int bytesRead;
        input.close();
        while ((bytesRead = input.read(buffer)) > 0)
        {
            responseBody.write(buffer, 0, bytesRead);
            
            throw new IOException();
        }
    }
    catch(IOException e)
    {
        System.out.println(e);
    }
}
英文:

would like to seek for help on my JUnit testing. On my method, I was able to cover all except the part where IOException needs to be thrown. I have done many workaround on this, but none of it seemed to work.

Here is the method where IOException was not covered on unit test

public String GetstrXMLValue(String strXML, String strCriteria) {
SAXBuilder builder = new SAXBuilder();
builder.setProperty(XMLConstants.ACCESS_S1, &quot;&quot;);
builder.setProperty(XMLConstants.ACCESS_S2, &quot;&quot;);
Document xmlDocument;
String strValue = &quot;&quot;;
ErrorHandler objErrHdl = new ErrorHandler();
try {
InputStream objStream = new ByteArrayInputStream(strXML.getBytes(&quot;UTF-8&quot;));
xmlDocument = builder.build(objStream);
XPathFactory xpath = XPathFactory.instance(); 
XPathExpression&lt;Object&gt; expr = xpath.compile(strCriteria);
List&lt;Object&gt; xPathSearchedNodes = expr.evaluate(xmlDocument);
if (xPathSearchedNodes.size() &gt; 0) {
Content content = (Content) xPathSearchedNodes.get(0);
strValue = content.getValue().toString();
}
} catch (JDOMException e) {
objErrHdl.LogError(this.getClass().getName(), &quot;GetstrXMLValue&quot;, &quot;ERROR RETRIEVING XML VALUES (XML=&quot; + strXML + &quot;;CRITERIA=&quot; + strCriteria + &quot;)&quot;, e.toString());
} catch (IOException e) {
objErrHdl.LogError(this.getClass().getName(), &quot;GetstrXMLValue&quot;, &quot;ERROR RETRIEVING XML VALUES (XML=&quot; + strXML + &quot;;CRITERIA=&quot; + strCriteria + &quot;)&quot;, e.toString());
} catch (Exception e) {
objErrHdl.LogError(this.getClass().getName(), &quot;GetstrXMLValue&quot;, &quot;ERROR RETRIEVING XML VALUES (XML=&quot; + strXML + &quot;;CRITERIA=&quot; + strCriteria + &quot;)&quot;, e.toString());
}
return strValue;
}

Here is my JUnit testing

@Test
public void testGetstrXMLValueThrowsIOException() throws IOException, ParserConfigurationException, SAXException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
OutputStream responseBody = new ByteArrayOutputStream();
String xml = &quot;&lt;?xml version=\&quot;1.0\&quot; encoding=\&quot;UTF-8\&quot;?&gt;\r\n&quot; + 
&quot;                &lt;RESULT&gt;\r\n&quot; + 
&quot;                &lt;SHORT_NAME&gt;XXXXXXXXXXXXX&lt;/SHORT_NAME&gt;\r\n&quot; + 
&quot;                &lt;ID_CODE&gt;9999999999999&lt;/ID_CODE&gt;\r\n&quot; + 
&quot;                &lt;/RESULT&gt;&quot;;
xmlHandler.XMLGenerateRootResult();
xmlHandler.GetstrXMLValue(xml, &quot;.//RESULT/ID_CODE/text()&quot;);
try
{
InputStream input = XMLHandlerTest.readXML(xml);
byte[] buffer = new byte[1024];
int bytesRead;
input.close();
while ((bytesRead = input.read(buffer)) &gt; 0)
{
responseBody.write(buffer, 0, bytesRead);
throw new IOException();
}
}
catch(IOException e)
{
System.out.println(e);
}

}

答案1

得分: 1

你的问题不太清楚。

你的意思是:如果发生IOException,如何使测试失败

不要捕捉它。测试用例的默认行为是,如果它抛出异常,那么该测试用例会被视为失败。请注意,System.out.println(e); 丢弃了关于错误的大量有用信息,而且意味着代码将继续执行。e.printStackTrace();LOG.something()System.out.println() 在捕获块中使用基本上总是错误的。停止这样做。如果你不能费心解决这个问题或者不知道怎么解决,捕获块中唯一正确的“我不知道”代码如下:

catch (Whatever e) {
    throw new RuntimeException("uncaught", e);
}

在这种情况下,完全删除 try/catch,如果发生 IOException,你的测试将会正确失败。

你的意思是:我需要测试我的方法是否在抛出 IOException 时能够执行正确的操作;我该如何测试它是否做正确的事情?

嗯,这没有意义,对吧?如果发生 IOException,你的方法显然是有问题的,因为你的方法会记录一些信息然后继续执行。这相当愚蠢,我认为没有必要向你解释如何编写一个单元测试,测试你的方法返回错误的伪造值并写入日志消息。我认为没有人实际上会想要那种行为。

让你的方法在出现错误时抛出异常,你可以使用 junit 轻松确认它是否执行了这个操作。为其编写自己的测试方法并进行注解:

@Test(expected = IOException.class)
public void testSomething() {
    if (Boolean.TRUE) throw new IOException();
    // 这个测试将会通过,因为我们说过
    // 它应该抛出 IOException。
}

你的意思是:如何让这个方法抛出 IOException?

这不容易实现,除非你有点破坏你的方法以使其变得可能。如果你停止捕捉异常并将它们转换为愚蠢的东西(一个日志消息并继续执行代码),代码覆盖率就不再是一个问题。完全摆脱那些捕获块。

英文:

Your question is unclear.

You meant: How do I make the test fail if an IOException occurs

By not catching it. The default behaviour of a test case, if it throws an exception, is that the test case is considered failed. Note that System.out.println(e); is tossing out a humongous amount of useful info about the error, AND means the code will keep going. e.printStackTrace();, LOG.something() or System.out.println() are basically always bugs if you do that in a catch block. Stop doing that. If you can't be bothered to deal with the problem or don't know how, the only correct 'I dunno' code in a catch block is this:

catch (Whatever e) {
throw new RuntimeException(&quot;uncaught&quot;, e);
}

In this case, just remove the try/catch entirely, and your test will properly fail if an IOException occurs.

You meant: I need to test my method if IT throws an IOException; how do I test that it does the right thing?

Well, there's no point, is there? Your method is obviously broken if an IOException happens, because your method will log something and just keep on going. That's rather silly, and I don't think it's useful for me to try to explain to you how to write a unit test that tests that your method returns the arbitrary misleading value and writes a log message. I don't think anybody would actually want that behaviour.

Make your method throw something on error, and you can easily confirm that it does this with junit. Give it its own test method and annotate:

@Test(expected = IOException.class)
public void testSomething() {
if (Boolean.TRUE) throw new IOException();
// this test will _PASS_, because we said
// it SHOULD throw IOException.
}

You meant: How do I make this method throw IOException?

That's not easily possible unless you kind of ruin your method to make it possible. If you stop catching exceptions and turning them into silly things (a log message and continuing with the code), the code coverage ceases to be an issue. Just get rid of those catch blocks entirely.

huangapple
  • 本文由 发表于 2020年9月30日 11:36:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/64130467.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定