Experience League Showcase
Read real-world use cases of Experience Cloud products written by your peers
Adobe Feedback Program
Influence Adobe product development
COMMUNITIES BY PRODUCT
Advertising
Analytics
Audience Manager
Campaign Classic v7 & Campaign v8
Campaign Standard
Developer
Experience Cloud
Experience Manager Sites & More
Experience Platform
Journey Optimizer
Target
Real-Time Customer Data Platform
Workfront
Creative Cloud
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)?
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.
@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
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>
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?