Presentation is loading. Please wait.

Presentation is loading. Please wait.

AEM & TDD It’s so boring… AUGUST 6, 2015

Similar presentations


Presentation on theme: "AEM & TDD It’s so boring… AUGUST 6, 2015"— Presentation transcript:

1 AEM & TDD It’s so boring… AUGUST 6, 2015
Всем привет! Рад что вы смогли выкроить время для меня, да еще в добавок после рабочего дня. Спасибо вам, мне не будет так скучно говорить. А то бы сидел сам и рассказывал Диме, коорый бы меня фоткал. Тема у меня про СКУКУ. Тема довольно заезженная на конференциях – юнит тесты, TDD, бла, бла, бла и прочее... Давайте писать ровнее, стройнее и более правильно. Я не буду напрягать рассказам о том как хорошо работать через TDD. Я сам не следую постоянно этой методологии и иногда лажаю. Пишу код и только потом тесты. Все мы не без греха. Но я точно знаю, что я в них верю. Вот скажите мне – что для вас юнит тесты? (спросить пару человек). Для меня, это в первую очередь – уверенность, что в % случаев после внесения изменений в код и при прохождении тестов и срабатывании теста на мою логику я могу спокойно уйти с работы быть уверенным, что СКОРЕЕ ВСЕГО ничего не поломал. Я прямо подчеркнул эти слова - СКОРЕЕ ВСЕГО. Но даже с этим скорее всего мне спиться спокойней. Ради этого самого спокойствия я поддерживаю тесты и даже переписываю полностью тесты на класс, когда нахожу на это время. А теперь про цель моей презентации. Она проста – рассказать вам что то новое и понять это самому немного глубже, ведь когда пытаешься кому то рассказать что то , понимаешь это лучше. И хотя тема немного не такая, как было заявлено, я смело поменял её, потому что нашел что то новое и хотел про это рассказать. Т.е. не только контент репозитории, но и AEM как таковой. Посмотрите сюда – (открыть проект и показать пример из пакета wrongmock – медленно скролить). Что тут у нас? А…. А ведь это из реального проекта… Как часто вы видите такие тесты? Это очень, очень трудозатратно такое писать. Иногда руки просто опускаються…

2 Testing AEM as JCR-based Applications
OSGi AEM SLING JCR JCR testing tools 1 Sling API level 2 OSGi API level 3 AEM application level 4 И конечно, глядя на такое мне хотелось найти пути уменьшить оверхэд при написании тестов. Убрать эти простыни моков, ну или хотя бы уменьшить их. Я решил посмотреть, что у нас есть сейчас на проекте и что можно использовать для того, что бы уменьшить количество времени затрачиваемого на написание тестов. При всём этом, проблему усиливает то, что у нас классы зачастую используют разные уровни API - JCR, Sling и AEM. Все видели классы разные методы которого работаю как с нодами так и с ресурсами SLING фреймворка. Для того что бы написать хорошие тесты нам надо чётко определять, с каким уровнем API мы работаем в классе и при необходимости отрефакторить класс. Давайте поёдем снизу вверх и рассмотрим, что мы можем использовать для своих нужд. К счастью, у нас не сильно большой выбор и потому я пошел по одной линейки самых лучших библиотек.

3 JCR: Dependency javax.jcr:jcr org.apache.jackrabbit:jackrabbit-core scope: test org.apache.jackrabbit:jackrabbit-jcr-commons scope:test Итак, давайте начнём с самого нижнего уровня - JCR репозитория. Часто мы ограничиваемся только библиотекой Mockito и иногда ИМЕЕТ смысл использовать ТОЛЬКО её. Но часто, нам надо тестировать не просто вызовы методов репозитория, а манипуляции с данными в репозитории. Просто вызов методов что нам даст то? Ну вроде как что то сделали с нодой, выставили свойство, поменял что то. А если мы вызвали еще один метод и выставили новое свойство? Проверили, что вызвалось свойство ноды с любой строкой как имя свойства и любой строкой как значение? А если мы забыли замокать метод? Мокито нам вообще не даст никакой информации. А методы которые складывают данные в репозиторий по определённой логике ? Так что же делать ? – Создавать реальные данные и тестировать логику манипуляции с данными. Многим, если не всем известен старый знакомый класс – TransientRepository из ядра бибилиотеки JCR. Что может быть лучше, чем реальный репозиторий для тестирования логики работы с репозиторием? TransientRepository стартует репозиторий после первого логина и останавливает его когда последняя сессия завершает свою работу. Репозиторий сам по себе стартует в памяти, что позволяет ему работать довольно быстро, но несмотря на это репозиторий создаёт структуру файлов на диске и при сохранении сессии сохраняет все данные в эту структуру. Конечно, работа с диском нежелательна, но это так называемый tradeoff. Что мы должны учитывать в нашем тесте ? Для того, что бы уменишить время обращения к диску, мы можем покладывать файл конфигурации, который иначе будет создаваться и записываться на диск при каждом старте в каждом тесте. Мы будем обязаны подкладывать CND файл с моделями данных нашего репозитория. Нам нужна будет административная сессия для создания тестовых данных и их очистки репозитория в ПРЕ / ПОСТ методах тест класса. На слайде я указал все зависимости которые будут нужны. Это сама спецификация JCR API, её имплементация Jackrabbit и Jackrabbit commons для более комфортной работе с репозиторием.

4 JCR: Example @ClassRule
public static TemporaryFolder TEMP_FOLDER = new TemporaryFolder(); @BeforeClass RepositoryConfig config = RepositoryConfig.create(configStream, TEMP_FOLDER.newFolder().getAbsolutePath()); TransientRepository REPOSITORY = new TransientRepository(config); Credentials credentials = new SimpleCredentials("admin", "admin".toCharArray()); REAL_SESSION = REPOSITORY.login(credentials, "default"); Я написал тест и постарался учесть все моменты и обьеденить лучшие практики в тесте. Основные точки класса которые нужно рассмотреть это временная директория, для того, что бы множественные запуски тестов не аффектили друг друга, если очистка репозитория проввалиться. Для этого можно использовать класс TemporaryFolder из бибилиотеки junit вместе с аннотацией ClassRule. Папочка созданная таким образом перед тестом будет уничтожаться после завершения тестов самим JUnit. Далее, можно создать конфигурационный файл репозитория. Конечно, он может создаваться автоматически, но почему бы не попробовать создать свой и использовать его для всех репозиториев ? Достаточно подложить его в ресурсы и использовать каждый раз. Далее, нам необходимы параметры доступа для административной сессии которую и будем по возможности использовать в тестах. После этого, необходимо загрузить CND файл, если он нам необходим. Все эти приготовления должны выполнятся в методе помеченной аннотацией BeforeClass для того, что бы не делать этого перед каждым тест методом. После этого в мы можем создавать структуру нод для тестирования и удалять их. После тестов, необходимо очистить тестовые данные для последующих тестов. С временнай директория всё просто - она будет очищена Junit в ином случае необходимо сделать это вручную. В методе помеченном необходимо завершить сессию. JUNit сам позаботится о том, что бу удалить репозиторий с диска при любом исходе тестов – провалятся они или нет. Открыть и показать файл DefaultFeedGenerationPersisterTest. В принципе это наверно единственный подход для тестирования логики классов работающих с репозиторием.

5 Resource Resolver Mocks 3
Apache Sling artifacts Sling testing tools 1 JCR Mocks 2 Resource Resolver Mocks 3 Sling Mocks 4 OSGi Mocks 5 Но мы часто обращаемся к хранилищу данные через API фреймворка Sling для которого те же ноды представлены в виде ресурсов. При этом мы можем адаптировать ресурсы к нодам и работать уже с ними. Это не совсем правильный подход, и это лично моё мнение, он обусловен не всегда удобной функциональность Sling или незнанием и неумением с ним работать. А часто и не желанием искать функционал, а работе по принципу – буду делать так, как знаю и ладно. Имитация двух уровней API еще более усложняют имитацию фреймворков и логики работы с ними. Но, к счастью, есть бибилиотеки которые много могут сделать за нас. В данном случае мы будем использовать бибилотеки написанные именно для тестов. При этом для нас есть целый ряд (5 штук) отдельных библиотек для тестов различного типа и уровня. Я их отсортировал примерно по возрастанию сложности. Первая библиотека Sling Testing Tools загружаеться как бандл предоставляет инструменты для следующих случаев: Запуск Unit тестов в OSGi контейнере. Наличие Sling фреймворка не обязателено и бандл может быть использован в различных реализациях OSGi контейнера, не только Apache Felix. Далее запуск тестов в запущенном инстансе Sling фреймворка. Запуск интеграционных тестов через HTTP вызовы как во время сборки так и отдельными командами в рабочем энве. JCR Mocks - библиотека которая облегчает нам написание тестов на репозиторий. Resource Resolver Mock – имитирует дерево ресурсов Sling фреймворка. Sling Mock - обладает более шировкими возможностями чем преведущая бибилотека и позволяет тестировать классы которые используют Sling API OSGi mocks позволяет тестировать классы использующие OSGi API. Я затрону ключевые моменты каждой библиотеки.

6 Sling Testing Utilities
public class YourTest extends RepositoryTestBase { RepositoryUtil.registerNodeType(getSession(), getClass().getClassLoader().getResourceAsStream("cq.cnd")); Node node = JcrUtil.createPath(“/etc/tags”, SLING_FOLDER, getSession()); } Sling testing tools предоставляет набор классов моков для различных уровней нашего приложения. В частности, для нас будет интересен базовый класс RepositoryTestBase ( смотрим ImprovedBrandsDAOTest) который позволяет вынести некоторые затраты на создание репозитория из наших тестов. Остальное для нас не столь важно. Давайте посмотрим на пример в классе ImprovedBrandsDAOTest org.apache.sling : org.apache.sling.commons.testing

7 org.apache.sling : org.apache.sling.testing.jcr-mock
JCR Mocks Supports: 1. Reading and writing all data (primitive values, arrays, binary data) via the JCR API; 2. Creating any number of nodes and properties (stored in-memory in a hash map); 3. Register namespaces; 4. Queries are supported by setting expected results for a given query; Not supported: 1. Node types are supported in the API, but their definitions and constraints are not applied; 2. Versioning not supported; 3. Transactions not supported; 4. Observation events can be registered but are ignored; 5. Access control always grants access; 6. Exporting/Importing data via document and system views not supported; 7. Workspace management methods not supported; Следующая бибилиотека JCR Mock уже имитирует работу с JCR API в нашем тестируемом классе. Т.е. логику работы с реальным репозиторием, но при этом реального репозитория не поднимаеться. Как всегда, у нас есть то, что поддерживаеться и то, что не поддерживаться Данная реализация поддерживает запись и чтение даннных. Создание любого количества нод и свойств в памяти. (по сути в мапе). Регистрация пространств имён. Частичная поддержка запросов через указание того какой результат будет возвращён. Не поддерживаеться Типы нод поддерживаються, но их структура или огрничения нет. Нет версионирования. Транзакции не поддериваються. Слушатели событий могут быть зарегестрированы, но выполнятся не будут. Не поддержки уровней доступа. Экспорт или импорт данных из документа или систему не поддерживается. Управление workspace не поддерживается. org.apache.sling : org.apache.sling.testing.jcr-mock

8 org.apache.sling : org.apache.sling.testing.jcr-mock
JCR Mocks Example // get session Session session = MockJcr.newSession(); // get repository Repository repository = MockJcr.newRepository(); // prepare mocked search result List<Node> resultNodes = ImmutableList.of(node1, node2, node3); // return this result for all queries MockJcr.setQueryResult(session, resultNodes); // return this result for a specific query MockJcr.setQueryResult(session, "your query statement", Query.JCR_SQL2, resultNodes); И рассмотрим совсем простенький примерчик. Всё взаимодействие происходит через обьект фабрику MockJcr, которая позволяет получать Моки различных обьектов. Например, сессии и репозитория. Тестовый репозиторий пустой и содержит только корневую ноду. Используя методы работы с репозиторием (утильные классы), мы можем создавать структуру необходимую для тестов. Если возникает необходимость тестировать запросы, то мы просто указываем предполагаемое значение которое будет возвращено. Либо, как альтернатива, можно указать каллбэк метод, который позволит динамически настроить возвращаемый набор нод в зависимости от переданного выражения. org.apache.sling : org.apache.sling.testing.jcr-mock

9 Resource Resolver Mocks
Supports: 1. All read and write operations of the Sling Resource API 2. Mimics transactions using via commit()/revert() methods 3. OSGi events for adding/changing/removing resources 4. The implementation tries to be as close as possible to the behavior of the JCR resource implementation e.g. concerning date and binary handling Not supported: 1. Authentication not supported ("login" always possible with null authentication info) 2. Querying with queryResources/findResources not supported (always returns empty result set) 3.Sling Mapping is not supported 5. Resolving resource super types Следующая библиотека позволяет создать Мок структуру виртуального дерева ресурсов из которой можно получить ResourceResolver и ResourceResolverFactory. Структура под капотом Sling Resource API использует обычную мапу в памяти для хранения всех данных. Эта структура поддерживает транзакционность используя методы commit и revert. Есть поддержка OSGi событий для добавления, изменения или удаления ресурсов. Эта имплементация написана так, что бы максимально близко имитировать поведение JCR реурсов, включая работу с датами и бинарными данными. Какой функционал не поддерживается: Аутонтефикация не поддерживается. Всегда имитируеться логин в репозиторий. Механизм запросов методами queryResources и findResources не поддерживается всегда возвращается пустой набор). Sling маппинг ресурсов на другие пути не поддеривается. Нет поддержкки наследования типов. Т.е. по сути при обычноей работе с ресурсами, нам этой бибилотечки достаточно. Давайте откроем класс ImprovedAgainJcrBrandsDAOImplTest метод shouldGetAllBrands() org.apache.sling : org.apache.sling.testing.resourceresolver-mock

10 org.apache.sling : org.apache.sling.testing.sling-mock
Sling Mocks Supports: 1. Reading and writing resource data using the Sling Resource API; 2. Backed by a mocked or real Jackrabbit JCR implementation; 3. Resource-JCR mapping or non-JCR mock implementation; 4. Registering adapter factories and resolving adaptions; 5. SlingScriptHelper mock implementation; 6. SlingHttpServletRequest and SlingHttpServletRequest; 7. MockModelAdapterFactory and MimeTypeService; Not supported: 1. It is not possible (nor intended) to really execute sling components/scripts and render their results, because the goal is to test supporting classes in Sling context, not the sling components/scripts themselves; Следуящая у нас большая библиотека которая затрагивает не только ресурсы, но и прочие аспекты работы Sling фреймворка. Используя эту библиотеку мы получаем дополнительно: Всё возможности преведущей библиотеки по работе с деревом ресурсов. НО!! Мы можем выбирать какой тип репозитория использовать в тестах. Про это немного далее. Библиотека базирована на различных имплементациях репозитория, как реального так и виртуального. Внутренний ресурс провайдер позволяет мапить ресурсы на JCR, если это необходимо. При этом можно использовать не JCR реализацию основанную на пакете бибилотеке ResourceResolver Mock который мы рассмотрели ранне. Мы можем регистрировать свои адаптеры и тестировать их. Реализация потоко безопасна , потому юнит тесты могу быть запущены паралельно. Мок SlingScriptHelper позволяет получить доступ к запросу, ответу и поддерживает получение OSGi сервиса из псевдо OSGi контейнера. Обьекты SlingHttpServletRequest и SlingHttpServletRequest позволяют устанавливать параметры запросы. В самом фреймворке реализованы некоторые псевдо сервисы, типа MockModelAdapterFactory и MimeTypeService Дополнительно добавлена правило SlingContext, которая позволяет интегрироваться в Junit. ContentLoader поддерживает импорт данных из JSON файлов и бинарных данных в нашу иерархию ресурсов. ContentBuilder позволяет легко создавать структуру тестовых данных. Что не поддерживается: Реальное исполнение скриптов Sling фреймворка и рэндер результатов, потому как основная цель всё таки протестировать классы в контексе. org.apache.sling : org.apache.sling.testing.sling-mock

11 org.apache.sling : org.apache.sling.testing.sling-mock
Sling Mocks: Example @Rule public final SlingContext context = new SlingContext(); @Test public void testSomething() { Resource resource = context.resourceResolver().getResource("/content/sample/en"); // further testing } RESOURCERESOLVER_MOCK 1 JCR_MOCK 2 NONE 3 JCR_JACKRABBIT 4 JCR_OAK 5 new SlingContext( ) Небольшой пример кода для вас. Создание обьект контекста и получение ресурс резолвера. Но, как я упомянул, мы можем играться с типами контекста. В зависимости от того какой тип мы выберем разные типы репозиториев будут доступны нам. По умолчанию используеться тип: RESOURCERESOLVER_MOCK. Мы указываем что хотим эмулировать дерево ресурсов в памяти как это делает преведущая библиотека. Быстрое и простое решение. JCR_MOCK создаёт дерево ресурсов и имитацию реаозитория которая базируется на JCR Mocks реализации, рассмотреной ранее. NONE – использует реализацию Sling Resource Factory без ResourceProvider ов. Необходимо регистрировать свои провайдеры которые будут предоставлять данные. Т.е. свои реализации интерфейса ResourceResolverFactory и ResourceResolver. Полезно только, если мы используеться другое хранилище данных. JCR_JACKRABBIT – использует реальный репозиторий из пакета sling.commons.testing, т.е. тот самый TransientRepository который мы рассматривали ранее. JCR_OAK – использует реальный репозиторий, только уже имплементацию Oak базирующийся на самой простой реализации MemoryNodeStore, которая хранит репоизторий в памяти. Все плюшки реального репозитория дают нам полный контроль над тестированием данных, хотя и занимает несколько секунд (миллисекунд?) для поднятия репозитория для каждого теста. При использовании реальных репозиториев необходимо помнить, что они не очищаются для каждого теста, потому необходимо это контролировать. Опять таки регистрация типов нод лежит на вас. Обе эти имплементации имею набор дополнительных зависимостей , которые надо подключить. Открыть ImprovedJcrProductsDAOImplTest org.apache.sling : org.apache.sling.testing.sling-mock

12 org.apache.sling : org.apache.sling.testing.sling-mock
Sling Mocks: Example // get a resource resolver ResourceResolver resolver = MockSling.newResourceResolver(); // get a resource resolver factory MockSling.newResourceResolverFactory(ResourceResolverType.RESOURCERESOLVER_MOCK); // get a resource resolver backed by a specific repository type ResourceResolver resolver = MockSling.newResourceResolver(ResourceResolverType.JCR_MOCK); И опять таки мы можем использовать обьект фактори для получения нужных нам обьектов. На этом примере – резолвер обычный и резолвер с типом. После того, как выбрали какой репозиторий вы хотите использовать для тестов, создаём его и создаём тестовые данные. Посмотрим как я это делаю в ImprovedAgainAndAgainJcrBrandsDAOImplTest для примера org.apache.sling : org.apache.sling.testing.sling-mock

13 Sling Mocks: Adapter Factories
// register adapter factory BundleContext bundleContext = MockOsgi.newBundleContext(); MockSling.setAdapterManagerBundleContext(bundleContext); bundleContext.registerService(myAdapterFactory); // test adaption MyClass object = resource.adaptTo(MyClass.class); // cleanup after unit test MockSling.clearAdapterManagerBundleContext(); Из дополнительных плюшек библиотеки, мы можем подключать свои классы адаптеры (пир этом вариант адаптации к моку тоже следует рассматривать) и тестировать их работу в контексте фреймворка. org.apache.sling : org.apache.sling.testing.sling-mock

14 Sling Mocks: Sling Helper, Response, request
SlingScriptHelper scriptHelper = MockSling.newSlingScriptHelper(); SlingHttpServletRequest request = scriptHelper.getRequest(); // get service MyService object = scriptHelper.getService(MyService.class); MockSlingHttpServletRequest request = new MockSlingHttpServletRequest(resourceResolver); request.setQueryString("param1=aaa&param2=bbb"); request.setResource(resourceResolver.getResource("/content/sample")); MockSlingHttpServletResponse response = new MockSlingHttpServletResponse(); Если наш класс получает OSGi сервис, то мы можем зарегестрировать его через BundleContext интерфейс реализация которого в JCR Mock пакете. Но, мы можем использовать обьект SlingScriptHelper через фабричный метод класса MockSling который предоставляет экземпляры реквеста, респонса и контекста бандла для тестирования. org.apache.sling : org.apache.sling.testing.sling-mock

15 Sling Mocks: Create or Import test data
ContentLoader contentLoader = new ContentLoader(resolver); contentLoader.json("/sample-data.json", "/content/sample/en"); // Import binary data from file in classpath contentLoader.binaryFile("/sample-file.gif", "/content/binary/sample-file.gif"); ContentBuilder contentBuilder = new ContentBuilder(resolver); contentBuilder.resource("/content/test1", ImmutableMap.<String, Object>builder() .put("prop1", "value1").put("prop2", "value2").build()); Еще одна из плюшек, которую мы видели уже – обьекты для быстрого создания тестового контента через импорт данных из JSON файла. Обьект лоадер достпен в  SlingContext через метод load(). При необходимости можно загрузить бинарные данные если мы манипулируем стримами в нашем классе. Данные будут сохранены в стандартых нодах типа nt:file/nt:resource или nt:resource. Напрмер этот код создаёт новый ресурс /content/binary/sample-file.gif (и, все вышележащие ресурсы) и импортирует бинарные данные в jcr:content дочернюю ноду. Второй обект – ContentBuilder для быстрого создания ресурсов вручную через методы билдера. Обьект билдер достпен в  SlingContext через метод build(). org.apache.sling : org.apache.sling.testing.sling-mock

16 org.apache.sling : org.apache.sling.testing.osgi-mock
Sling Mocks: OSGi Supports: 1. Bundle, BundleContext and ComponentContext objects and navigate between them; 2. Register services; 3. Reading metadata from /OSGI-INF/<pid>.xml and from /OSGI-INF/serviceComponents.xml; 4. Apply service configuration provided in unit test and from SCR metadata; 5. Inject dependencies - static and dynamic; 6. Call lifecycle methods for activating, deactivating or modifying; 7. Service and bundle listener implementation; 8. Mock implementation of LogService which logs to SLF4J in JUnit context; 9. Mock implementation of EventAdmin which supports EventHandler services; И последняя библиотека позволяет использовать мок обьект OSGi контейнер. Т.е типа бандл обьект, конекст бандла и взаимодействие между ними. В итоге регистрируя свои сервисы мы можем тестировать получение ссылок на них и работу с ними. Бибилиотека позволяе читать и разбирать метаинформацию по сервисам из XML файлов что позволяет применять конфигурацию на сервис. Поддерживает внедрение зависимостей на основе аннотаций, как статичискую, так и динамическую. Наш псевдо контейнер вызывает методы активации, модификации и деактивации компонента среды OSGi. Возможно регистрировать слушатели на сервисы и бандлы. Контейнер содержит моковую имплментацию LOGService который логирует информацию через SLF4J в контексте Junit тестов и моковую имплементацию EventAdmin а который поддерживает регистрацию EventHandler ов сервисов. org.apache.sling : org.apache.sling.testing.osgi-mock

17 Sling Mocks: OSGi Example
public class OSGiExampleTest { @Rule private final OsgiContext context = new OsgiContext(); @Test public void testSomething() { // register and activate service MyService service1 = context.registerInjectActivateService(new MyService(), ImmutableMap.<String, Object>of("prop1", "value1")); // get service instance OtherService service2 = context.getService(OtherService.class); } Простенький пример использовани конекста. Создание нового контекста, добавление и активация нового класса и получение экземпляра сервиса. org.apache.sling : org.apache.sling.testing.osgi-mock

18 Sling Mocks: OSGi Example
BundleContext bundleContext = MockOsgi.newBundleContext(); BundleContext bundleContext = MockOsgi.newComponentContext(properties, ImmutableMap.<String, Object>of("prop1", "value1")); // register service bundleContext.registerService(MyClass.class, myService, properties); // get service instance ServiceReference ref = bundleContext.getServiceReference(MyClass.class.getName()); MyClass service = bundleContext.getService(ref) При использовании фабричного метода класса MockOsgi позволяет получить различные обьекты моки – бандл контекст, компонент контекст и прочее. Так же поддерживаеться симуляция регистрации сервисов в контексте. org.apache.sling : org.apache.sling.testing.osgi-mock

19 Sling Mocks: OSGi Example
// get mock bundle context BundleContext bundleContext = MockOsgi.newBundleContext(); // create service instance manually MyService testedService = new MyService(); // inject dependencies MockOsgi.injectServices(testedService, bundleContext); // activate service MockOsgi.activate(testedService, props); // test service... // deactivate service MockOsgi.deactivate(testedService); При работе с конекстом необходим быть уверенным, что регистрируешь сервисы в правильном порядке по цепочке зависимостей. Только динамические ссылки будут автоматическо обработаны в не зависимости от порядка регистрации классов. Метод injectServices, activate и deactivate могут работать правильно только когда метаданные в XML файле найдены в текущем пути загрузки классов в OSGI-INF директории. Как вы знете они генерируються автоматически плагином Maven SCR и выложены по правильно пути другим плагином, типа assemble. org.apache.sling : org.apache.sling.testing.osgi-mock

20 wcm.io : io.wcm.testing.aem-mock
И вот надо идти глубже, вернее подниматься в наших абстракциях. Тестировать работу с AEM.И здесь нам может помочь бибилотека WCM.IO. wcm.io : io.wcm.testing.aem-mock

21 wcm.io : io.wcm.testing.aem-mock
Supports: 1. Mocked OSGi, JCR and Sling environment provided by the Apache Sling project; 2. Implementation of AEM API level (PageManager, Page, Template, ComponentManager, Component, TagManager, Tag, Designer, Asset and Rendition); 3. JUnit rule AemContext; 4. Full support for Sling Models; 5. Setting run modes; 6. Layer adapter factory; Not supported: 1. Other parts of the AEM API; Что она поддерживате ? The mock implementation supports: Access to mocked OSGi, mocked JCR and mocked Sling environment provided by the Apache Sling project. Т.е. по сути ко всему, что мы рассматривали ранее. Implementation of AEM WCM API objects PageManager, Page, Template, ComponentManager, Component, TagManager, Tag, Designer Implementation of AEM DAM API objects Asset and Rendition JUnit rule AemContext for easy access to all context objects and registering adapter factories and OSGi services Full support for Sling Models Setting run modes Layer adapter factory The following features are not supported: Other parts of the AEM API wcm.io : io.wcm.testing.aem-mock

22 wcm.io : io.wcm.testing.aem-mock
WCM.IO: Example public class ExampleTest { @Rule public final AemContext context = new AemContext(); @Test public void testSomething() { Resource resource = context.resourceResolver().getResource("/content/sample/en"); Page page = resource.adaptTo(Page.class); // further testing } Простенький пример. Всё наше взаимодействие происходит через обьект AemContext который создаётся JUnit правилом. Обьект сам заботится об инициализациях и очистки для того что бы наши тесты проходили чисто и независимо. И если надо, паралельно. Мы можем комбинировать юнит тесты с и фреймворком Mockito. Класс AemContext предоставляет следующие обьекты и функционал, которые он, правильно, берёт из прочих библиотек рассмотренных ранее и наследует весь их фунционал. OSGi Component Context, OSGi Bundle Context, Sling Resource Resolver, Sling Request, Sling Response, Sling Script Helper Registering OSGi services, Registering adapter factories, Accessing JSON Importer wcm.io : io.wcm.testing.aem-mock

23 wcm.io : io.wcm.testing.aem-mock
WCM.IO: Example public class ExampleTest { @Rule public final AemContext context = new AemContext(); @Test public void testSomething() { context.pageManager().create("/content/sample/en", "test1", "/apps/sample/templates/homepage", "title1"); //… Page page = context.pageManager().getPage("/content/sample/en"); Template template = page.getTemplate(); Iterator<Page> childPages = page.listChildren(); // further testing context.pageManager().delete(page, false); } А вот и простой пример использования AEM API методов в Юнит тестах wcm.io : io.wcm.testing.aem-mock

24 wcm.io : io.wcm.testing.aem-mock
WCM.IO: Example public final AemContext context = new AemContext(new SetUpCallback()); private static final class SetUpCallback implements AemContextCallback { @Override public void execute(final AemContext context) throws PersistenceException, IOException { // application-specific services for unit tests context.registerService(AdapterFactory.class, new AppAdapterFactory()); context.registerService(new AemObjectInjector()); // import sample content context.contentLoader().json("/sample-content.json", "/content/sample/en"); // set default current page context.currentPage("/content/sample/en"); } При построении юнит тестов для приложения мы обычно используем какие либо специфические задачи, такие как регистрация сервисов, адапетров и импорт контента. Для того, что бы сделать тесты более чистыми мы можем использовать каллбэк классы в которых будет реализован необходимый функционал. wcm.io : io.wcm.testing.aem-mock

25 Q&A? Вот и всё. Спасибо!


Download ppt "AEM & TDD It’s so boring… AUGUST 6, 2015"

Similar presentations


Ads by Google