Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

Unable to inject mandatory reference in aem unit testing.

Avatar

Level 2

Hi,

I followed this AEM tutorial https://experienceleague.adobe.com/docs/experience-manager-learn/cloud-service/developing/advanced/s...

to set up a service class that loads once service user object is available. 

 

 

 

 

@Component(
        reference = {
                @Reference(
                        name = wknd-examples-statistics,
                        service = ServiceUserMapped.class,
                        target = "(subServiceName=wknd-examples-statistics)"
                )
        }
)
public class ContentStatisticsImpl implements ContentStatistics {

 

 

 

 

My service works fine. The issue is when I am unit testing.

I get this error while unit testing:

org.apache.sling.testing.mock.osgi.ReferenceViolationException: Unable to inject mandatory reference 'wknd-examples-statistics' (org.apache.sling.serviceusermapping.ServiceUserMapped) for class com.adobe.aem.wknd.examples.core.statistics.impl.ContentStatisticsImpl

: no matching services were found. bundleContext=org.apache.sling.testing.mock.osgi.MockBundleContext@298f7b0a.

 

Error occurs when I inject the service as below:

context.registerInjectActivateService(newContentStatisticsImpl());

How do i mock @reference. Please help

1 Accepted Solution

Avatar

Correct answer by
Level 2

Hi, I resolved it by adding a bind method:

@Component(
        reference = {
                @Reference(
                        name = wknd-examples-statistics,
                        service = ServiceUserMapped.class,
                        target = "(subServiceName=wknd-examples-statistics)",
                        bind = "setServiceUserMapped"
                )
        }
)
public class ContentStatisticsImpl implements ContentStatistics {
   @Reference
    private ServiceUserMapped serviceUserMapped;

    public void setServiceUserMapped(ServiceUserMapped serviceUserMapped) {
        this.serviceUserMapped = serviceUserMapped;
    }
//other code
}

Test case:
public class ContentStatisticsImplTest {
       @BeforeEach
        public void setup() {
        serviceUserMapped = mock(ServiceUserMapped.class);
        context.registerService(ServiceUserMapped.class,serviceUserMapped, ImmutableMap.of(ServiceUserMapped.SUBSERVICENAME,"wknd-examples-statistics"));
}

Thanks for your help. @sherinregi 

View solution in original post

6 Replies

Avatar

Community Advisor

Hi @sindhusr 

One thing i notice here is you are trying yo use registerInjectActivateService on the same class you are on. In your case you are referencing a markerservice serviceusermapped and that reference needs to be mocked inorder to prevent this exception .

 

Can you try to do inject that and use the same in setup and then invoke

 

Try something similar 

sherinregi_0-1704780939754.png

 

https://programtalk.com/java-more-examples/io.wcm.testing.mock.aem.junit.AemContext.registerService(...

Ref: https://developer.adobe.com/experience-manager/reference-materials/6-5/javadoc/org/apache/sling/serv...

 

Thanks,

Sherin

 

Avatar

Level 2

Hi @sherinregi , Thank you for your response.

What is ServiceUserMapped.clreplaced? I cannot resolve that on my IDE nor can I find references to it.

This is what I tried:

ServiceUserMapped serviceUserMapped = Mockito.mock(ServiceUserMapped.class);
context.registerService(ServiceUserMapped.class,serviceUserMapped,ImmutableMap.of(ServiceUserMapped.SUBSERVICENAME,"wknd-examples-statistics"));
context.registerInjectActivateService(newContentStatisticsImpl());

 Now I get the below error:

java.lang.RuntimeException: No bind/unbind method name or file name defined for reference wknd-examples-statistics

 

Avatar

Community Advisor

Hi @sindhusr 

You can ignore the clreplaced one. The steps you followed looks rite to me . The error now you are getting looks a different one and i feel it could be related to the details given in the below links. Could you please check on that 

https://groups.google.com/g/wcm-io-dev/c/JzFnXsY6XZk?pli=1

 

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/runtime-error-while-runnin...

 

They have explained a sequence of steps to follow. Also check the import packages for mock 

ref: https://programtalk.com/vs4/java/adobe/commerce-cif-connector/bundles/cif-virtual-catalog/src/test/j...

 

 

 

Avatar

Correct answer by
Level 2

Hi, I resolved it by adding a bind method:

@Component(
        reference = {
                @Reference(
                        name = wknd-examples-statistics,
                        service = ServiceUserMapped.class,
                        target = "(subServiceName=wknd-examples-statistics)",
                        bind = "setServiceUserMapped"
                )
        }
)
public class ContentStatisticsImpl implements ContentStatistics {
   @Reference
    private ServiceUserMapped serviceUserMapped;

    public void setServiceUserMapped(ServiceUserMapped serviceUserMapped) {
        this.serviceUserMapped = serviceUserMapped;
    }
//other code
}

Test case:
public class ContentStatisticsImplTest {
       @BeforeEach
        public void setup() {
        serviceUserMapped = mock(ServiceUserMapped.class);
        context.registerService(ServiceUserMapped.class,serviceUserMapped, ImmutableMap.of(ServiceUserMapped.SUBSERVICENAME,"wknd-examples-statistics"));
}

Thanks for your help. @sherinregi 

Avatar

Community Advisor

Hi @sindhusr 
when unit testing OSGi components that have@Reference annotations, you need to simulate the OSGi environment and register the services your component depends on. The error you're encountering indicates that the required service (wknd-examples-statistics) is not being provided in the test environment.
You can use the @Designate annotation along with @OsgiService to mock and register the required service during unit testing. Here's an example:

import org.apache.sling.serviceusermapping.ServiceUserMapped;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

@Component(
        immediate = true,
        service = ContentStatistics.class
)
@Designate(ocd = ContentStatisticsImpl.Config.class)
public class ContentStatisticsImpl implements ContentStatistics {

    @Reference
    private ServiceUserMapped wkndExamplesStatisticsService;

    // Other code...

    @Activate
    @Modified
    protected void activate(Config config) {
        // Your activation logic
    }

    // Configuration interface
    @ObjectClassDefinition(name = "Content Statistics Configuration")
    public @interface Config {

        @AttributeDefinition(name = "Sub Service Name", description = "The sub-service name")
        String subServiceName() default "wknd-examples-statistics";
    }
}

 

you can then use @OsgiServiceto mock and register the required service:

 

 

import org.apache.sling.serviceusermapping.ServiceUserMapped;
import org.junit.jupiter.api.Test;
import org.apache.sling.testing.mock.osgi.MockOsgi;

class ContentStatisticsImplTest {

    @Test
    void testContentStatistics() {
        // Mock the ServiceUserMapped service
        ServiceUserMapped wkndExamplesStatisticsService = MockOsgi
                .newService(ServiceUserMapped.class)
                .property("subServiceName", "wknd-examples-statistics")
                .build();

        // Register the mocked service
        MockOsgi.injectServices(new ContentStatisticsImpl(), wkndExamplesStatisticsService);

        // Your test logic here
    }
}

This approach allows you to simulate the OSGi environment and register the required services for your unit tests.

Thanks.