Is it Possible to test service methods with AEM Cloud? | Community
Skip to main content
Level 8
May 25, 2023

Is it Possible to test service methods with AEM Cloud?

  • May 25, 2023
  • 3 replies
  • 2053 views

We have many services which do things like call apis on external systems.

Currently, the only way we can test these end to en is to write servlets which call the services, and run the servlets via postman or similar.

 

What would be helpful is a way to:

1. use services in tests (without mocking them - using the full proper service)

2. be able to create a request to pass into services which are expecting it.

3. to have the tests only run on local builds, not on AEM builds (because AEM build servers wont have whitelisted IPs)

4. to be able to run a specific test only (via command line)

 

Which test framework is AEM using?

 

Obviously you cant just use a service in a test like you would in a servlet, e.g. this test wont work:

 

public class SomeServiceTest {

@Reference
private SomeService someService;

@Test
void someTest() throws Exception {
String result = someService.somecall(someparam);
}

}

 

We found an example like this:

  @Rule
  public final AemContext context = new AemContext();

// register OSGi service
context.registerService(MyClass.class, myService); // or alternatively: inject dependencies, activate and register OSGi service context.registerInjectActivateService(myService); // get OSGi service MyClass service = context.getService(MyClass.class);

But we cant resolve "Rule, and we are not sure if we need all 3 of those lines, or just one of them, and what MyClass is (is it the service class, or the test class, or another class)?

 

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.

3 replies

aanchal-sikka
Community Advisor
Community Advisor
May 25, 2023

Hello @tb3dock 

 

The video attached is using AemContext to test services. Please review once:

https://www.youtube.com/watch?v=BtLqsd1MDhY

 

You would have to mock at the point where you are getting the result from Third party like a Json.

For example, in our code the requests and response with an External App is done by a separate service. We mock that result.

 

when(apiEndpointServiceMock.makeApiCall(any(Map.class))).thenReturn(apiResultsJson);

  Before and after this statement, we are using AemContext for:

- all validations before making a call

- post-processing of the results.

Aanchal Sikka
TB3dockAuthor
Level 8
May 26, 2023

Thanks for the reply. The crux is we dont want to mock any of the endpoints - we need to test the endpoint as an end to end test, i.e. an integration test.  we are hoping there is a way to get a handle on a service and call it.

aanchal-sikka
Community Advisor
Community Advisor
May 26, 2023

@tb3dock :

 

Anything in the blog [0], that could help you?

https://cqdump.joerghoh.de/integration-tests-with-aem/ 

Aanchal Sikka
rawvarun
Community Advisor
Community Advisor
May 25, 2023
TB3dockAuthor
Level 8
May 26, 2023

Thanks for the link, there are some useful examples in there, but I cant find the main one - how to call a service from a test.

Community Advisor
May 26, 2023

@tb3dock

This is a basic skeleton of Test class which you can use. You don't need to use @Rule annotation here.

 

import io.wcm.testing.mock.aem.junit5.AemContext; import io.wcm.testing.mock.aem.junit5.AemContextExtension; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(AemContextExtension.class) public class TestClass { public final AemContext aemContext = new AemContext(); private ServiceUnderTest service; @BeforeEach void setup(AemContext context) { service = aemContext.registerInjectActivateService(new ServiceUnderTestImpl()); } @Test void testMethod(){ service.serviceMethodCall(); } }

 

 Those three lines you have shared are different ways of registering and getting service class object in test classes. 1st and 3rd line should be used together or you can just use 3rd line. It does both register and inject service.  

Alternatively you can pass configuration as well like below, if there is any in your service.

 

Map<Object,Object> config = new HashMap<Object,Object>(); config.put("property1","value1"); config.put("property2",Boolean.FALSE); service = aemContext.registerInjectActivateService(new ServiceUnderTestImpl(),config );

 

 Hope this helps.

Thanks

Swapnil

TB3dockAuthor
Level 8
May 28, 2023

Thanks this is very helpful, but when I do this I get this error:

 

[ERROR] myTest  Time elapsed: 0.004 s  <<< ERROR!

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [io.wcm.testing.mock.aem.junit5.AemContext arg0] in method [void com.mycompan.MyTest.setup(io.wcm.testing.mock.aem.junit5.AemContext)].

 

I think its because of the parameter to setup.  If I remove that parameter, I get a this error:

 

org.apache.sling.testing.mock.osgi.ReferenceViolationException: Unable to inject mandatory reference 'myService' for class com.bedegaming.eyas.aem.core.services.impl.MyServceImpl : no matching services were found.

 

In the root pom I see this:

 

<dependency>
<groupId>io.wcm</groupId>
<artifactId>io.wcm.testing.aem-mock.junit5</artifactId>
<version>3.0.2</version>
<scope>test</scope>
</dependency>

 

TB3dockAuthor
Level 8
May 28, 2023

The crux is this: the service we want to test calls another service, and this other service does not get instantiated, so the tests fail with:

 

org.apache.sling.testing.mock.osgi.ReferenceViolationException: Unable to inject mandatory reference 'myOtherService' for class com.myCompany.impl.MyServiceImpl : no matching services were found.

 

Ive tried all 4 ways to inject MyService into the tests, but all result in MyService not being able to resolve MyOtherService.

 

CAn AEM not handle this case?