TeamCity поддерживает jUnit «на лету» и особых проблем с выполнением тестов нет. Но стандартная поддержка не покрывает все юзкейсы. Например, никогда нельзя быть уверенным, в какой очередности пройдут тесты. Кроме того, есть другие вариации тестовой архитектуры, которые просто невозможно сделать дефолтными средствами jUnit. Например, определение в рантайме, какие тесты нужно запускать, а какие нет. Причем с выводом в отчетах в TeamCity без проигнорированных тестов.
Это иногда действительно смущает. У меня была ситуация, когда были написаны тесты для тестирования веб-сервера и все работало хорошо. Но как-то сам веб-сервер упал (в тестах не было логики по остановке / запуску веб-сервера), но часть тестов в репортах TeamCity были отмечены как успешные (так отмечаются в списке все проигнорированные). Естественно заказчик сказал «What the...».
Вроде бы ничего сложного — исп��льзовать сервисные сообщения TeamCity. Но в TeamCity есть официальная бага, при которой сервисные сообщения в TestOutput не читаются.
Для удобства создадим кастомный класс для вывода сообщений. Чтобы передать команду в TeamCity, необходимо отправить ее в стандартный out поток.
Каждая группа тестов должна быть размещена в блоке TestSuite, используя команды 'testSuiteStarted' и 'testSuiteFinished'. Каждый тест должен начинаться с 'testStarted' и заканчиваться с 'testFinished'. Тест будет считаться успешным, если внутри тестового блока не будет команды 'testFailed'.
Более подробно о поддерживаемых сервисных сообщениях в TeamCity можно почитать тут.
Теперь мы можем писать тесты так:
Так как об ошибках мы сообщаем вручную, то есть смысл их перехватывать. Иначе они просто проигнорируются, и TeamCity, не дождавшись команды testFailed, будет считать тест успешным.
Тут все стандартно. Единственный момент — таск 'junit' должен содержать 'showoutput=«yes»'. Это заставит выводить в стандартный out поток TestsOuput.
Так как TeamCity не читает сервисные команды из TestOutput junit`а, нужно вообще отключить распознавание junit тестов. Для этого необходимо открыть build configuration, перейти во вкладку 'Build parameters' и добавить такие параметры:
Вот и все. Теперь можно извращаться над тестами jUnit в TeamCity как угодно.
Это иногда действительно смущает. У меня была ситуация, когда были написаны тесты для тестирования веб-сервера и все работало хорошо. Но как-то сам веб-сервер упал (в тестах не было логики по остановке / запуску веб-сервера), но часть тестов в репортах TeamCity были отмечены как успешные (так отмечаются в списке все проигнорированные). Естественно заказчик сказал «What the...».
Вроде бы ничего сложного — исп��льзовать сервисные сообщения TeamCity. Но в TeamCity есть официальная бага, при которой сервисные сообщения в TestOutput не читаются.
1. Вывод сообщений
Для удобства создадим кастомный класс для вывода сообщений. Чтобы передать команду в TeamCity, необходимо отправить ее в стандартный out поток.
public class Log { public static void logTCTestSuiteStart( String message ) { System.out.println( "##teamcity[testSuiteStarted name='" + message + "']" ); } public static void logTCTestSuiteFinished( String message ) { System.out.println( "##teamcity[testSuiteFinished name='" + message + "']" ); } public static void logTCTestStart( String message ) { System.out.println( "##teamcity[testStarted name='" + message + "']" ); } public static void logTCTestFinished( String message ) { System.out.println( "##teamcity[testFinished name='" + message + "']" ); } public static void logTCTestFailed( String message, AssertionError e ) { System.out.println( "##teamcity[testFailed name='" + message + "' message='" + e.getMessage() + "']" ); } }
Каждая группа тестов должна быть размещена в блоке TestSuite, используя команды 'testSuiteStarted' и 'testSuiteFinished'. Каждый тест должен начинаться с 'testStarted' и заканчиваться с 'testFinished'. Тест будет считаться успешным, если внутри тестового блока не будет команды 'testFailed'.
Более подробно о поддерживаемых сервисных сообщениях в TeamCity можно почитать тут.
2. Простой тест
Теперь мы можем писать тесты так:
public class BasicTests1 { BasicTester tester = new BasicTester( {constructor_args} ); @BeforeClass public static void setUp() { tester.initialize(); } @Test public void orderedTestRun() throws Exception { Log.logTCTestSuiteStart( "Basic tests" ); tester.testOne(); tester.testTwo(); tester.testThree(); Log.logTCTestSuiteFinished( "Basic tests" ); } @AfterClass public static void tearDown() { tester.dispose(); } } public class BasicTester { protected {field1}; protected {field2}; protected {field3}; protected BasicTester( {class_fields} ); protected void testOne() { Log.logTCTestStart( "testOne" ); try { //test logic } catch( AssertionError e ) { Log.logTCTestFailed( "testOne", e ); } Log.logTCTestFinished( "testOne" ); } protected void testTwo() { Log.logTCTestStart( "testTwo" ); try { //test logic } catch( AssertionError e ) { Log.logTCTestFailed( "testTwo", e ); } Log.logTCTestFinished( "testTwo" ); } protected void testThree() { Log.logTCTestStart( "testThree" ); try { //test logic } catch( AssertionError e ) { Log.logTCTestFailed( "testThree", e ); } Log.logTCTestFinished( "testThree" ); } }
Так как об ошибках мы сообщаем вручную, то есть смысл их перехватывать. Иначе они просто проигнорируются, и TeamCity, не дождавшись команды testFailed, будет считать тест успешным.
3. Ant task
Тут все стандартно. Единственный момент — таск 'junit' должен содержать 'showoutput=«yes»'. Это заставит выводить в стандартный out поток TestsOuput.
4. Настройки билда TeamCity
Так как TeamCity не читает сервисные команды из TestOutput junit`а, нужно вообще отключить распознавание junit тестов. Для этого необходимо открыть build configuration, перейти во вкладку 'Build parameters' и добавить такие параметры:
- system.teamcity.ant.junit-support.enabled = false
- system.teamcity.ant.testng-support.enabled = false
Вот и все. Теперь можно извращаться над тестами jUnit в TeamCity как угодно.
