JMockit не соответствует записанному ожиданию

Я пытаюсь издеваться над методами SAXParser.parse(...) с помощью JMockit.

Я могу успешно настроить ожидания для сигнатуры метода parse(InputStream, DefaultHandler), но когда я пытаюсь смоделировать сигнатуру parse(InputSource, DefaultHandler), JMockit никогда не видит вызов и выдает исключение MissingInvocation.

В следующем примере показаны два тестовых случая, один из которых имитирует вариант InputSource, а другой — вариант InputStream:

public class SAXTest {

    @Test(expected=RuntimeException.class)
    public void testParseInputSource(@Mocked final SAXParser saxParser) throws Exception {
        new Expectations() {{
            saxParser.parse((InputSource) any, (DefaultHandler) any); result = new RuntimeException("Fail now");
        }};

        SAXParser p = SAXParserFactory.newInstance().newSAXParser();
        InputSource isource = new InputSource(new StringReader("<test/>"));
        p.parse(isource, new DefaultHandler());    
    }

    @Test(expected=RuntimeException.class)
    public void testParseInputStream(@Mocked final SAXParser saxParser) throws Exception {
        new Expectations() {{
            saxParser.parse((InputStream) any, (DefaultHandler) any); result = new RuntimeException("Fail now");
        }};

        SAXParser p = SAXParserFactory.newInstance().newSAXParser();
        InputStream istream = new ByteArrayInputStream("</test>".getBytes());
        p.parse(istream, new DefaultHandler());
    }
}

Запуск тестового примера приводит к:

    JUnit version 4.12
E.
Time: 0.069
There was 1 failure:
1) testParseInputSource(SAXTest)
java.lang.Exception: Unexpected exception, expected<java.lang.RuntimeException> but was<mockit.internal.MissingInvocation>
        at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
 ...
Caused by: Missing 1 invocation to:
javax.xml.parsers.SAXParser#parse(any org.xml.sax.InputSource, any org.xml.sax.helpers.DefaultHandler)
   on mock instance: $Subclass_SAXParser_param0@490d6c15
Caused by: Missing invocations
        at javax.xml.parsers.SAXParser.parse(SAXParser.java)
        at SAXTest$1.<init>(SAXTest.java:20)
        at SAXTest.testParseInputSource(SAXTest.java:19)

FAILURES!!!
Tests run: 2,  Failures: 1

Как видите, версия InputSource дает сбой, а версия InputStream работает как положено.

Я использую Junit 4.12 и JMockit 1.32.


person eakst7    schedule 08.06.2017    source источник


Ответы (1)


TL;DR

Используйте аннотацию @Capturing вместо @Mocked в тесте InputSource.

Пояснение

Ваша проблема в том, что метод SAXParser.parse(InputSource, DefaultHandler) переопределяется методом SAXParserImpl. Поскольку вы используете аннотацию @Mocked, вы издеваетесь только над методами класса SAXParser.

SAXParserFactory.newInstance().newSAXParser() возвращает SAXParserImpl, поэтому для метода InputStream, поскольку нет переопределения, он переходит к фиктивному методу SAXParser.parse(InputStream, DefaultHandler).

НО, для метода InputSource, поскольку есть переопределение, он переходит к не издевательскому методу и, следовательно, к отсутствующему вызову.

Если бы вы использовали аннотацию Capturing, которая имитирует интерфейс/класс и все его подклассы/подреализации, у вас не будет отсутствующего исключения вызова.

person Alfergon    schedule 09.06.2017
comment
Верно. За исключением того, что вплоть до JMockit 1.32 многие внутренние классы JRE из нестандартных пакетов (например, com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl) исключены из @Capturing из-за прошлых проблем с надежностью. Однако в JMockit 1.33 будет разрешено com.sun.org. При этом IMO издевается над синтаксическим анализатором XML, и его лучше избегать. - person Rogério; 10.06.2017
comment
Я использую 1.8, поэтому не заметил этого: P - person Alfergon; 12.06.2017