AEM Unit Test for servlet | Community
Skip to main content
Level 6
December 13, 2021

AEM Unit Test for servlet

  • December 13, 2021
  • 4 replies
  • 6581 views

I have to write a Unit Test for a servlet that uses 

 

@Reference
private transient SearchService searchService;

When I run the doGetTest I get a NullPointerException since this searchService is null:


@Test
void doGetTest() throws IOException {

MockSlingHttpServletRequest request = context.request();
MockSlingHttpServletResponse response = context.response();
underTest.doGet(request, response);

How do I inject this SearchService in my Unit Test?

Thanks in advance.

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

4 replies

Kiran_Vedantam
Community Advisor
Community Advisor
December 13, 2021

Hi @anasustic 

 

Try to mock the service in your test class as mentioned here : https://taylor.callsen.me/unit-testing-aem-sling-models-and-servlets/

 

Hope this helps!

 

Thanks,

Kiran Vedantam.

milind_bachani
Adobe Employee
Adobe Employee
December 13, 2021

Hi @anasustic ,

You can use @Mock annotations for creating the mock instance of the service as:

@Mock
SearchService mockSearchService;

Then you can initialize your mocks using initMocks() in setUp() as:

@Before
public void setUp() throws Exception {
     MockitoAnnotations.initMocks(this);
}

And then inside test you can use :

servlet.searchService = mockSearchService;

Hope this helps, thanks!

anasusticAuthor
Level 6
December 13, 2021

Thanks @milind_bachani but I do not unterstand how to do 

servlet.searchService = mockSearchService;

My servlet does not have a method searchService? 

December 13, 2021
import org.mockito.internal.util.reflection.Whitebox;

Whitebox.setInternalState(underTest, "searchservice", mockedSearchservice);
Vijayalakshmi_S
Level 10
December 13, 2021

Hi @anasustic,

Use @Mock (org.mockito.Mock) annotation on the Service in  Test class and to inject this to the servlet under test, use @InjectMocks (org.mockito.InjectMocks) on the servlet instantiation like the below. 

 

@Mock
private SearchService searchService

@InjectMocks
private SimpleServlet underTest = new SimpleServlet();

Then in the doGetTest() method, before calling underTest.doGet(request, response) -> provide mock implementation for the searchService using when and thenReturn methods. 

Please update this thread in case of any issues. 

 

anasusticAuthor
Level 6
December 13, 2021

I do not understand what do you mean by


mock implementation for the searchService using when and thenReturn methods. 

Please update this thread in case of any issues. 

 


This is what I have 

@ExtendWith(AemContextExtension.class)
class LocationFinderByTitleServiceTest {


private final AemContext context = ComponentTestContext.createAemContext();

@Mock
SearchService searchService;

@InjectMocks
private LocationFinderByTitleService underTest = new LocationFinderByTitleService();

@BeforeEach
void beforeEach() {
context.load().json("/component/content/location/content.json", "/content/de");


Map<String, Object> pm = new HashMap<>();
pm.put("title", "Shop");
context.request().setMethod("GET");
context.request().setParameterMap(pm);
}


@Test
void doGetTest() throws IOException {

MockSlingHttpServletRequest request = context.request();
MockSlingHttpServletResponse response = context.response();


underTest.doGet(request, response);

 I am getting a NullPointerException in the underTest.doGet while the searchService is null.

anasusticAuthor
Level 6
December 14, 2021

You might be using some method/functionality of SearchService in your actual Servlet class, you need to provide implementation for the same here to the test class. 

Example: If you have searchService.search() and that returns a List object say for example, then we need to write

when(searchService.search()).thenReturn(any(List.class));

 

Also, in the snippet you have shared, instantiate the AemContext like below 

private AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);

or

private AemContext context = new AemContext(ResourceResolverType.JCR_MOCK);

 


I did as you suggested and in the beforeEach() added:

context.registerInjectActivateService(new SearchService(),  "prop1", "value1");

The SearchService() has itself two @3214626 annotations. 

@Reference
private ResourceResolverService resourceResolverService;

@Reference
private GeocodingService geocodingService;

and now I am getting 

org.apache.sling.testing.mock.osgi.ReferenceViolationException: Unable to inject mandatory reference 'geocodingService' for class ....SearchService : no matching services were found.

 

Can you please suggest how to properly mock these two references?

BrianKasingli
Community Advisor and Adobe Champion
Community Advisor and Adobe Champion
December 13, 2021

Try this

 


...
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

private SearchService searchService;

@Test
void doGetTest() throws IOException {
searchService = mock(SearchService.class);
when(searchService.get(any()).thenReturn(null);
MockSlingHttpServletRequest request = context.request();
MockSlingHttpServletResponse response = context.response();
underTest.doGet(request, response);

JsonObject jsonResponse = gson.fromJson(response.getOutputAsString(), JsonObject.class);
assertNotNull(jsonResponse.get("searchResults"));
}

 

anasusticAuthor
Level 6
December 14, 2021

My SearchService class has two @3214626 annotations

 

@Reference
private ResourceResolverService resourceResolverService;

@Reference
private GeocodingService geocodingService;

and two public methods with the following signatures:

public List<LocationResult> getResults(@Nonnull GoogleMapsApiConfigurationModel configModel, @Nonnull String pagePath, @Nullable String zipCity)

 

public void cacheLocations(Resource resource)

 I am not sure how to mock that in 

when(searchService.getResults(???).thenReturn(???)