отчеты об ошибках утверждений JUnit с помощью настраиваемых сообщений

Я создавал модульные тесты, используя JUnit в Eclipse, и основные принципы JUnit мне ясны. Тесты выполняются так, как должны, и теперь пришло время найти хороший способ сообщить о неудачных тестах. В большинстве примеров, которые я встречаю в Интернете, используется какая-то встроенная система, такая как Ant, Maven или Hudson, для запуска тестов одновременно с созданием проекта, но эта интеграция не требуется в процессе сборки. Тесты должны иметь возможность запускаться независимо от системы сборки. В конце концов, эти системы просто берут информацию, которую они получают от JUnit, и помещают ее в красивый макет HTML.

Я узнал, что информацию JUnit можно прочитать, создав пользовательский прослушиватель с помощью класса RunListener JUnitCore и обрабатывать сбои по мере их возникновения с помощью метода testFailure. При создании своих тестов я всегда предоставлял собственное сообщение об ошибках утверждения. Моя проблема в том, что это сообщение не отображается в трассировке сбоев JUnit. Вместо этого трассировка сбоя будет показывать «java.lang.Exception: не удалось вызвать *». Когда я смотрю на консоль, я вижу ту же трассировку стека, но ниже также следует строка, которой предшествует «Вызвано: *», и здесь я вижу свое собственное сообщение об ошибке.

Caused by: java.lang.AssertionError: <my custom error message>
    at *

Поскольку я только начинаю работать с JUnit и не знаю, является ли это нормальным поведением JUnit или что-то не так в том, как я реализовал свои тесты, и должен ли я просто видеть свои пользовательские сообщения в трассировке сбоев? Я также заметил, что когда я обнаруживаю ошибку утверждения в методе, в котором я выполняю тест, я МОГУ получить доступ к сообщению, используя «error.getMessage()». Поэтому, если необходимо, это было бы решением, а также позволило бы мне включить в отчет дополнительную информацию, доступную в тот момент, когда я поймал ошибку (например, URL-адрес веб-страницы и т. д.), но поместив блок try-catch вокруг каждого утверждения. по моему мнению, помешает его цели.

Как я уже сказал, я новичок в модульном тестировании, а также в разработке Java в целом, поэтому очень вероятно, что я делаю несколько глупых ошибок. Любые указатели очень приветствуются!

Обновление 2: ниже приведена анонимная версия трассировки стека на консоли. Может быть, это поможет прояснить мой вопрос.

    java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at xxxxx.xxxxxxxxxxxx.xxxxxxxxx(xxxxxxxxxxx.java:103)
        at xxxxx.xxxxxxxxxxxxxx.xxxxxx(xxxxxxxxxxx.java:62)
        at junit.framework.TestCase.runBare(TestCase.java:134)
        at junit.framework.TestResult$1.protect(TestResult.java:110)
        at junit.framework.TestResult.runProtected(TestResult.java:128)
        at junit.framework.TestResult.run(TestResult.java:113)
        at junit.framework.TestCase.run(TestCase.java:124)
        at xxxxx.xxxxxxxxxxxx.xxxxx(xxxxxxxxxxxx.java:90)
        at junit.framework.TestSuite.runTest(TestSuite.java:243)
        at junit.framework.TestSuite.run(TestSuite.java:238)
        at xxxxx.xxxxxxxxxxxxxxxxxxxx.xxxx(xxxxxxxxxxxxxxxx.java:87)
        at junit.framework.TestSuite.runTest(TestSuite.java:243)
        at junit.framework.TestSuite.run(TestSuite.java:238)
        at xxxxx.xxxxxxxxxxxxxxxxxxxxxx.xxxxx(xxxxxxxxxxxxxx.java:87)
        at junit.framework.TestSuite.runTest(TestSuite.java:243)
        at junit.framework.TestSuite.run(TestSuite.java:238)
        at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
    Caused by: java.lang.AssertionError: <xx my custom message xx>.
        at xxx.xxxxxxxx.xxxxxxxxxxxxxx(xxxxxxxx.java:100)
        ... 27 more

Ниже представлена ​​анонимная версия трассировки стека, о которой сообщает JUnit java.lang.Exception: не удалось вызвать действие на текущей странице.

java.lang.Exception: could not invoke action <xx action name xxx> on current page class xxxx.xxxxxxx: [Ljava.lang.StackTraceElement;@71d382ab
at xxxxx.xxxxxxxxxxxxxxxxx.xxxxx(xxxxxxxxxxxxxxxxxxxx.java:65)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at xxxxx.xxxxxxxxxxxxxxxxx.xxxxx(xxxxxxxxxxxxxxxxxxxx.java:90)
at junit.framework.TestSuite.runTest(TestSuite.java:243)
at junit.framework.TestSuite.run(TestSuite.java:238)
at xxxxx.xxxxxxxxxxxxxxxxx.xxxxx(xxxxxxxxxxxxxxxxxxxx.java:87)
at junit.framework.TestSuite.runTest(TestSuite.java:243)
at junit.framework.TestSuite.run(TestSuite.java:238)
at xxxxx.xxxxxxxxxxxxxxxxx.xxxxx(xxxxxxxxxxxxxxxxxxxx.java:87)
at junit.framework.TestSuite.runTest(TestSuite.java:243)
at junit.framework.TestSuite.run(TestSuite.java:238)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:83)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:24)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
at org.junit.runner.JUnitCore.run(JUnitCore.java:117)
at xxxxx.<xx class that initiates the RunListener xx>.main(<xx class that initiates the RunListener xx>.java:11)

person pascie    schedule 31.07.2012    source источник


Ответы (1)


Тесты должны иметь возможность запускаться независимо от системы сборки.

Тест будет независимым, даже если вы используете систему сборки. Его цель — облегчить вашу жизнь в долгосрочной перспективе, поэтому я предлагаю вам рассмотреть возможность его использования. Я предлагаю maven, который мне сначала не понравился, потому что он говорит вам, как размещать такие вещи, как каталоги, но теперь я вижу, что это упрощает вашу жизнь.

Когда я смотрю на консоль, я вижу ту же трассировку стека, но ниже также следует строка, которой предшествует «Вызвано: *», и здесь я вижу свое собственное сообщение об ошибке.

Большинство инструментов удаляют это, поэтому вы видите только то, что вам нужно. например в большинстве IDE вы можете щелкнуть трассировку стека и перейти к строке кода, которая вызывает проблему. Если вы используете maven, среда IDE будет синхронизирована с вашей конфигурацией maven, чтобы она могла найти ответственный код.

Я также заметил, что когда я обнаруживаю ошибку утверждения в методе, в котором я выполняю тест, я МОГУ получить доступ к сообщению, используя «error.getMessage()».

Вам не нужно делать ничего из этого, если вы используете maven и/или IDE.

очень вероятно, что я делаю какие-то глупые ошибки.

Похоже, это не так. Я бы посоветовал вам использовать инструменты, которые используют большинство разработчиков (например, IDE и maven), и большинство этих проблем решаются за вас. (Также многие другие проблемы, о которых вы, возможно, никогда не знали;)

person Peter Lawrey    schedule 31.07.2012
comment
Спасибо за быстрый ответ @peter. Я вижу преимущества использования системы сборки, но это разовое задание, для которого знакомство с этими системами сборки стоило бы мне слишком много времени. Поскольку тесты JUnit выполняются зависимо, и я должен иметь доступ ко всей информации об ошибках/сбоях через созданный мной прослушиватель, кто-нибудь знает, есть ли способ настроить прослушиватель, чтобы он показывал мне пользовательские сообщения, а не удалял их из стека? след? - person pascie; 31.07.2012
comment
Я думал, что вы указали, что они находятся в вашей трассировке стека, а не наверху. Попробуйте вместо этого использовать e.getCause().getMessage(). Никогда не было подходящего времени для изучения системы сборки, это просто то, на что вам нужно найти время;) - person Peter Lawrey; 31.07.2012
comment
Вызванная часть действительно отображается в моем стеке ошибок в окне консоли, но трассировка сбоя, предоставляемая JUnit, похоже, обрывает ее. А метод failure.getMassage() возвращает описание исключения в первой строке трассировки стека. Я попытался использовать failure.getCause().getMessage() в методе testFailure() моего слушателя, и когда я запускаю его, внутри метода testFailure() больше ничего не выполняется. @Peter Спасибо за работу над решением здесь со мной! - person pascie; 31.07.2012
comment
Я считаю, что JUnit работает так, как ожидалось, но я должен выяснить, почему он сообщает о том, что ему не удается вызвать метод, а не об основной причине, которая заключается в провале моего теста утверждений. - person pascie; 31.07.2012
comment
Это совсем не то, о чем говорит указанное вами исключение. Можете ли вы показать нам исключение, в котором говорится, что ему не удалось вызвать метод? - person Peter Lawrey; 31.07.2012
comment
Извините, вначале я не заметил разницы в выводе консоли и трассировке стека, сообщаемой JUnit. Я добавляю их обоих в вступительный пост. - person pascie; 31.07.2012
comment
Хорошо, я наконец взломал его. В одном из родительских классов, который в итоге вызвал метод, в котором выполнялась проверка утверждения, для перехвата InvocationTargetExceptions использовался блок try-catch. Это скрывало мои более подробные ошибки, обнаруженные JUnit! - person pascie; 31.07.2012