Всем привет!
Чтобы после моей предыдущей статьи о тестировании пайплайнов Jenkins не сложилось впечатления, что проблем нет и провалидированный IDEA, скомпилированный и оттестированный JUnit и Pipeline Unit тестами код сразу заработает в Jenkins - вот три больших ложки дегтя. Уточню, речь про scripted pipeline.
1) CPS. Детально что это за зверь написано тут https://www.jenkins.io/doc/book/pipeline/cps-method-mismatches/
Суть в том, что при выполнении код пайпа интерпретируется специальным образом, чтобы в любой момент на диске лежал актуальный слепок текущего состояния пайпа и можно было восстановить состояние после рестарта Jenkins. К слову, по моему опыту это не всегда работает, возможно пайпы кривые, возможно есть проблемы с плагинами. При этом далеко не весь вызываемый в runtime код можно так трасформировать, т.е. весь код делится на CPS и NonCPS. Не трансформируется Java standart library код, конструкторы и методы, помеченные @NonCPS. И есть правило - NonCPS код не может вызывать CPS код.
На модульном тесте это проверить невозможно, функционал PipelineUnit для этого по факту не работает.
2) Groovy DSL. Код пишется не на Groovy, а на Groovy DSL, а это две большие разницы) ну может не совсем большие, но точно разницы. Т.е. почитав доки по Groovy ты видишь там разные крутые фичи, думаешь - о, а у него есть плюсы по сравнению в Java, пробуешь их использовать - и облом. Вот некоторые примеры:
а) не работает with
б) не работают traits
в) не работает ссылка на метод через .& - используем {}. В принципе это даже более Groovish, но факт остается фактом
г) переопределять методы enum в пайпе нельзя https://issues.jenkins.io/browse/JENKINS-48722
д) использовать @MapConstructor тоже нельзя https://issues.jenkins.io/browse/JENKINS-45901
е) без аннотации map constructor тоже не работает
Как видно, на некоторые проблемы заведены баги, которые не решаются годами. Подозреваю, по двум причинам - разработчики фокусируются на declarative pipeline и трудоемкость исправления
3) Sandbox. В целях безопасности на большинстве нормально настроенных Jenkins включен режим Sandbox https://www.jenkins.io/doc/book/managing/script-approval/
Суть в том, что код запускается в песочнице, где разрешен вызов методов по whilelist. Есть возможность добавить в whitelist новые методы, но нужно апрувить каждый (!) метод. В зависимости от типа среды и компании это может быть трудоемко. Предположим, решили вы использовать новый Java DataTime API, написали 10 строк кода, вызвали пяток метод и все пять приходится апрувить. И узнаешь об этом также только когда выполнение кода дошло до нужного метода.
По моему опыту именно на разруливание этих трех проблем тратится максимум времени при отладке пайпа.
#devops #jenkins #unittest #debug
Чтобы после моей предыдущей статьи о тестировании пайплайнов Jenkins не сложилось впечатления, что проблем нет и провалидированный IDEA, скомпилированный и оттестированный JUnit и Pipeline Unit тестами код сразу заработает в Jenkins - вот три больших ложки дегтя. Уточню, речь про scripted pipeline.
1) CPS. Детально что это за зверь написано тут https://www.jenkins.io/doc/book/pipeline/cps-method-mismatches/
Суть в том, что при выполнении код пайпа интерпретируется специальным образом, чтобы в любой момент на диске лежал актуальный слепок текущего состояния пайпа и можно было восстановить состояние после рестарта Jenkins. К слову, по моему опыту это не всегда работает, возможно пайпы кривые, возможно есть проблемы с плагинами. При этом далеко не весь вызываемый в runtime код можно так трасформировать, т.е. весь код делится на CPS и NonCPS. Не трансформируется Java standart library код, конструкторы и методы, помеченные @NonCPS. И есть правило - NonCPS код не может вызывать CPS код.
На модульном тесте это проверить невозможно, функционал PipelineUnit для этого по факту не работает.
2) Groovy DSL. Код пишется не на Groovy, а на Groovy DSL, а это две большие разницы) ну может не совсем большие, но точно разницы. Т.е. почитав доки по Groovy ты видишь там разные крутые фичи, думаешь - о, а у него есть плюсы по сравнению в Java, пробуешь их использовать - и облом. Вот некоторые примеры:
а) не работает with
б) не работают traits
в) не работает ссылка на метод через .& - используем {}. В принципе это даже более Groovish, но факт остается фактом
г) переопределять методы enum в пайпе нельзя https://issues.jenkins.io/browse/JENKINS-48722
д) использовать @MapConstructor тоже нельзя https://issues.jenkins.io/browse/JENKINS-45901
е) без аннотации map constructor тоже не работает
Как видно, на некоторые проблемы заведены баги, которые не решаются годами. Подозреваю, по двум причинам - разработчики фокусируются на declarative pipeline и трудоемкость исправления
3) Sandbox. В целях безопасности на большинстве нормально настроенных Jenkins включен режим Sandbox https://www.jenkins.io/doc/book/managing/script-approval/
Суть в том, что код запускается в песочнице, где разрешен вызов методов по whilelist. Есть возможность добавить в whitelist новые методы, но нужно апрувить каждый (!) метод. В зависимости от типа среды и компании это может быть трудоемко. Предположим, решили вы использовать новый Java DataTime API, написали 10 строк кода, вызвали пяток метод и все пять приходится апрувить. И узнаешь об этом также только когда выполнение кода дошло до нужного метода.
По моему опыту именно на разруливание этих трех проблем тратится максимум времени при отладке пайпа.
#devops #jenkins #unittest #debug
Pipeline CPS Method Mismatches
Jenkins – an open source automation server which enables developers around the world to reliably build, test, and deploy their software
Всем привет!
Я подозреваю почти все знают и используют такой фреймворк, как Mockito. По крайней мере судя по собеседованиям, которые я провожу и коду, который вижу)
Наверняка все знают mock, spy, when(...).thenAnswer.
Но я хотел бы рассказать про ряд его малоизвестных особенностей:
1) можно создавать тестовые двойники через Mockito.mock или Mockito.spy, а можно воспользоваться аннотациями над полями класса: @Mock и @Spy, главное не забыть вызвать MockitoAnnotations.openMocks(testClass); перед каждым вызовом тестового метода
2) Mockito с версии 2 научился mock-ать final методы и классы
3) Mockito также научился mock-ать static методы. Что ж, PowerMock теперь не нужен) Да, остаются private методы, но во-первых я бы их не тестировал, а во-вторых если очень надо - есть рефлексия
4) через verify можно делать сложные проверки поведения: что методы какого-то класса не вызывались, что вызывались только определенные методы класса и ничего более, сколько раз вызывался метод, с какими аргументами. Здесь главное не переборщить и не сделать тест слишком хрупким. Разделять тестирование бизнес-процесса и детали реализации
5) с помощью ArgumentCaptor можно захватить содержимое передаваемого в mock параметра и проанализировать его отдельными assert-ами. Полезно для сложных объектов или для анализа содержимого строки
6) как известно, двойники, созданные с помощью mock, по умолчанию не возвращают ничего при вызове метода, т.к. вызова не происходит. Можно захардкодить ответ в помощью Mockito.when(...).thenReturn. Но если нужно вернуть значение в зависимости от входных параметров, а настраивать реальный объект не хочется - есть два варианта: создать наследника интерфейса Answer, где в методе answer сформировать ответ, либо сделать то же самое c использованием Streams API и Mockito.when(...).thenAnswer
Когда искал ссылки для поста, нашел отличную статью, где описываются практически все описанные выше лайфхаки: https://habr.com/ru/post/444982
Ну разве что кроме mock static https://www.baeldung.com/mockito-mock-static-methods и возврата сложного ответа из mock при помощи Answer https://www.baeldung.com/mockito-mock-methods
Пост будет дополняться полезными фичами по мере их нахождения)
Как говорить читать не перечитать https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
Stay tuned)
#unittest #mockito
Я подозреваю почти все знают и используют такой фреймворк, как Mockito. По крайней мере судя по собеседованиям, которые я провожу и коду, который вижу)
Наверняка все знают mock, spy, when(...).thenAnswer.
Но я хотел бы рассказать про ряд его малоизвестных особенностей:
1) можно создавать тестовые двойники через Mockito.mock или Mockito.spy, а можно воспользоваться аннотациями над полями класса: @Mock и @Spy, главное не забыть вызвать MockitoAnnotations.openMocks(testClass); перед каждым вызовом тестового метода
2) Mockito с версии 2 научился mock-ать final методы и классы
3) Mockito также научился mock-ать static методы. Что ж, PowerMock теперь не нужен) Да, остаются private методы, но во-первых я бы их не тестировал, а во-вторых если очень надо - есть рефлексия
4) через verify можно делать сложные проверки поведения: что методы какого-то класса не вызывались, что вызывались только определенные методы класса и ничего более, сколько раз вызывался метод, с какими аргументами. Здесь главное не переборщить и не сделать тест слишком хрупким. Разделять тестирование бизнес-процесса и детали реализации
5) с помощью ArgumentCaptor можно захватить содержимое передаваемого в mock параметра и проанализировать его отдельными assert-ами. Полезно для сложных объектов или для анализа содержимого строки
6) как известно, двойники, созданные с помощью mock, по умолчанию не возвращают ничего при вызове метода, т.к. вызова не происходит. Можно захардкодить ответ в помощью Mockito.when(...).thenReturn. Но если нужно вернуть значение в зависимости от входных параметров, а настраивать реальный объект не хочется - есть два варианта: создать наследника интерфейса Answer, где в методе answer сформировать ответ, либо сделать то же самое c использованием Streams API и Mockito.when(...).thenAnswer
Когда искал ссылки для поста, нашел отличную статью, где описываются практически все описанные выше лайфхаки: https://habr.com/ru/post/444982
Ну разве что кроме mock static https://www.baeldung.com/mockito-mock-static-methods и возврата сложного ответа из mock при помощи Answer https://www.baeldung.com/mockito-mock-methods
Пост будет дополняться полезными фичами по мере их нахождения)
Как говорить читать не перечитать https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
Stay tuned)
#unittest #mockito
Хабр
Mockito и как его готовить
О статье Перед вами очередное руководство по Mockito. В нём я, с одной стороны, попытался описать функционал этой библиотеки так, чтобы незнакомый с нею читатель сразу получил возможность полноценно...