
It’s difficult to imagine a modern software application that can live without JUnit tests. In a previous article on JUnit testing, JUnit Tests for WCMUsePojo Objects, we included a tip involving a project we were working on. For this article, we use the same project and extend the approach with sling models and a direct connection to a real AEM repository.
In our case, we encountered a problem when we had to test a big back-end service that had a lot of dependencies with other services, data, and web content inside a JCR repository. Creating JUnit tests for AEM components and services requires preparing tons of data, so we implemented a solution that helps save time in preparing all of this data. We were able to use a real repository and data prepared in AEM using all of AEM’s capabilities. This solution significantly sped up writing tests and improved the quality of tests.
Connecting a JUnit test to AEM is a no-brainer requiring just a few simple steps:
- Download a class package https://github.com/apache/sling-org-apache-sling-testing-sling-mock-oak/tree/master/src/main/java/org/apache/sling/testing/mock/sling/oak
- Include the WEB DAV repository factory
org.apache.jackrabbit:jackrabbit-jcr2dav
dependency in your pom.xml file - Modify the OakMockSlingRepository class from the first step to use the ProxyRepository Connection. Here’s just the changed code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
private SimpleCredentials simpleCredentials; private ProxyRepository proxyRepository; @Activate protected void activate(BundleContext bundleContext) { executor = Executors.newSingleThreadExecutor(); scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); if (bundleContext.getServiceReference(Executor.class) == null) { bundleContext.registerService(Executor.class, executor, null); } try { simpleCredentials = new SimpleCredentials("[AEM user]", “[password]”); proxyRepository = new ProxyRepository(mode.getPath() + "/crx/server"); Session session = proxyRepository.login(simpleCredentials); repository = session.getRepository(); } catch (Exception e) { //TODO } } public Session loginAdministrative(String workspaceName) throws RepositoryException { return proxyRepository.login(simpleCredentials);//you possibly want to use admin creds } |
Now you can declare an AemContext Test Rule in your test cases:
1 2 |
@Rule public AemContext context = new AemContext(ResourceResolverType.JCR_OAK); |
It will use your AEM Repository for tests. Almost anything is possible now, just use a real repository path and adapt to page or sling model:
1 2 3 4 5 6 7 8 9 |
@Test public void slingModelTest() throws IOException { Resource resource = context.resourceResolver(). getResource("/content/blueprint/junit/page"); Page page = resource.adaptTo(Page.class); ComponentSlingModel model = page.getContentResource(). getChild("main-par/buttoncompone").adaptTo(ComponentSlingModel.class); //TODO } |
Tips for Additions
Here is a list of nice tips for additions to your tests’ base class that can help you with complex tests:
OSGi configs for the test context
1 2 3 4 |
ConfigurationAdmin сonfigurationAdmin = context.getService(ConfigurationAdmin.class); Dictionary<String, Object> properties = new Hashtable<String, Object>(); properties.put("[key]", "value"); сonfigurationAdmin.getConfiguration("configuration PID").update(properties); |
Run modes for the test context
1 2 3 4 5 |
MockSlingSettingService settingService = (MockSlingSettingService) context.getService(SlingSettingsService.class); Set<String> runModes = new HashSet<>(); Collections.addAll(runModes, "author", "qa"); settingService.setRunModes(runModes); |
Add package with models (useful examples for ACS lists)
1 |
context.addModelsForPackage("com.adobe.acs.commons.genericlists"); context.addModelsForClasses(GenericList.class); |
Inject and Activate services (any of your real services or external services like GenericListAdapterFactory)
1 2 3 |
context.registerInjectActivateService(new com.adobe.acs.commons.genericlists.impl.GenericListAdapterFactory()); context.registerInjectActivateService(new MyCacheServiceImpl()); |
Register any AEM Mock Service without activation, just to satisfy dependencies
1 |
context.registerService(CryptoSupport.class, new MockCryptoSupport()); |
Supply the context and sling models with sling request related objects
1 2 3 4 5 6 7 8 |
Resource mockRequestRes = context.resourceResolver().getResource("/[path]/anypage"); context.request().setResource(resource); context.request().setServletPath("[sevlet path]"); Page page = anyResource.adaptTo(Page.class); anyExampleModel.setRequest(context.request()); anyExampleModel.setCurrentPage(page); anyExampleModel.setSlingScriptHelper(context.slingScriptHelper()); |
Author: Peter Zhuravlev