Expand my Community achievements bar.

How to unit test OSGi service with ReferencePolicy=DYNAMIC using AEMContext

Avatar

Level 2

Hi,

   I have an OSGi service (MyService) that is referencing a list of OSGi services implementing the same interface (SecondService). Debugging this code with AEM 6.5.17.0 is properly injecting all the OSGi services (serviceList has multiple objects), but when I try to replicate that in my unit test using AEMContext.registerService() to inject multiple OSGi services, I see that the reference variable is not getting injected properly. What am I doing wrong? 
Here is a sample code for the MyService where the serviceList is getting injected properly on my local AEM instance.

 

package com.mypackage;

import org.osgi.service.component.annotations.*;
import java.util.*;

@Component(service = MyService.class,immediate = true)
public class MyServiceImpl implements MyService
{
    @reference(service = SecondService.class,
            cardinality = ReferenceCardinality.MULTIPLE,
            policy = ReferencePolicy.DYNAMIC,
            bind = "bindMethod",
            unbind = "unbindMethod")
    private volatile List<SecondService> serviceList;
    protected void bindMethod(){ //DO SOMETHING }
    protected void unbindMethod(){ //DO SOMETHING }
}

 

And the sample code for the unit tests that doesn't inject serviceList properly. 

 

package com.mypackage;

import io.wcm.testing.mock.aem.junit.AemContext;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
    @Rule
    public final AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
    @Mock
    SecondService s1;
    @Mock
    SecondService s2;
    @test
    public void sampleTest(){
        context.registerService(SecondService.class, s1);
        context.registerService(SecondService.class, s2);

        MyService service = context.registerInjectActivateService(new MyServiceImpl());
    }
}

 

In both cases (local debug and unit test), I am debugging the MyService.bindMethod() to check whether the serviceList is injected or not. 

Regards,
Raj

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

9 Replies

Avatar

Community Advisor

Hi @rajdevms 

You are missing the updated method in your MyServiceImpl class. The updated method is called by the OSGi container when the service is updated. In your case, when you register the services in the unit test, the updated method is not called, and hence the serviceList is not getting updated.

Please check this changes

 

package com.mypackage;

import org.osgi.service.component.annotations.*;
import java.util.*;

@Component(service = MyService.class,immediate = true)
public class MyServiceImpl implements MyService
{
    @reference(service = SecondService.class,
            cardinality = ReferenceCardinality.MULTIPLE,
            policy = ReferencePolicy.DYNAMIC,
            bind = "bindMethod",
            unbind = "unbindMethod")
    private volatile List<SecondService> serviceList;
    protected void bindMethod(){ //DO SOMETHING }
    protected void unbindMethod(){ //DO SOMETHING }
    
    @Activate
    protected void activate() {
        //DO SOMETHING
    }

    @Deactivate
    protected void deactivate() {
        //DO SOMETHING
    }

    @Modified
    protected void updated() {
        //DO SOMETHING
    }
}

 

 



Avatar

Level 2

Hi @Raja_Reddy ,
    Thank you for your response. Can you help me understand why adding the updated() method would solve the problem? 
    The code that I shared before works as expected in AEM run-time but does not when running the unit test. So, the solution for this problem would involve changing the unit test and not the actual OSGi service. 

Regards,

Raj

Avatar

Community Advisor

Hi @rajdevms 

Adding the `updated()` method to your OSGi service implementation would not solve the problem with your unit test. The `updated()` method is called by the OSGi framework when the configuration of the service is updated. It is used to handle any changes to the configuration properties of the service.

If your code works as expected in AEM run-time but not in the unit test, it is possible that the unit test environment is not properly configured or that there are differences in the environment that are causing the issue. You may need to modify your unit test to properly simulate the AEM run-time environment.



Avatar

Level 2

that is exactly what I looking for. How do I fix this `it is possible that the unit test environment is not properly configured or that there are differences in the environment that are causing the issue. You may need to modify your unit test to properly simulate the AEM run-time environment.`

Avatar

Community Advisor

@rajdevms ,you need to extend your unit test with AemContext extension which will make your unit test to run in mock AEM environment. Please refer for more details https://wcm.io/testing/aem-mock/usage.html

Avatar

Level 2

Hi @sravs, I am already using AemContext, if you look at the MyServiceTest class, it is leveraging AemContext. Please let me know if I am missing something from your suggestion. 

Regards,

Raj

Avatar

Administrator

@rajdevms Did you find the suggestions from users helpful? Please let us know if more information is required. Otherwise, please mark the answer as correct for posterity. If you have found out solution yourself, please share it with the community.



Kautuk Sahni

Avatar

Level 2

Hi @kautuk_sahni, I have only received a single response and that hasn't solved my problem. This post should stay active. 

Avatar

Level 1

What worked for me was a different signature of the method registerService

context.registerService(class, instance, props)

if to go with your example

context.registerService(SecondService.class, s1, new HashMap<>());