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.
Views
Replies
Total Likes
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.
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!
Thanks @milind_bachani but I do not unterstand how to do
servlet.searchService = mockSearchService;
My servlet does not have a method searchService?
import org.mockito.internal.util.reflection.Whitebox;
Whitebox.setInternalState(underTest, "searchservice", mockedSearchservice);
Unfortunatelly I do not have the option to import Whitebox in maven.
Hi @anasustic ,
That is initialization of referenced service in test servlet class.
This is analogous to :
// any referenced service can be initialized by mock using following
servlet.<referenced_service_obj_name> = <mock_service_name>;
Let me know if you still need help, thank you.
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.
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.
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 @reference 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?
Register those two Services as well to the AemContext object just before injecting the SearchService.
context.registerService(ResourceResolverService.class, <<instantiation of the service impl/mocked reference>>); context.registerService(GeocodingService.class, <<instantiation of the service impl/mocked reference>>); context.registerInjectActivateService(new SearchService(), "prop1", "value1");
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"));
}
My SearchService class has two @reference 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(???)
I did as you suggested
@Test
void doGetTest() throws IOException {
searchService = mock(SearchService.class);
GoogleMapsApiConfigurationModel model = new GoogleMapsApiConfigurationModel();
String one = "one";
String two = "two";
when(searchService.getResults(model, one, two)).thenReturn(null);
MockSlingHttpServletRequest request = context.request();
MockSlingHttpServletResponse response = context.response();
underTest().doGet(request, response);
I am getting the following error when I run the test:
at org.apache.sling.testing.mock.osgi.OsgiServiceUtil.injectServiceReference(OsgiServiceUtil.java:435)
at org.apache.sling.testing.mock.osgi.OsgiServiceUtil.injectServices(OsgiServiceUtil.java:418)
at org.apache.sling.testing.mock.osgi.MockOsgi.injectServices(MockOsgi.java:163)
at org.apache.sling.testing.mock.osgi.context.OsgiContextImpl.registerInjectActivateService(OsgiContextImpl.java:155)
at org.apache.sling.testing.mock.osgi.context.OsgiContextImpl.registerInjectActivateService(OsgiContextImpl.java:143)
Views
Like
Replies
Views
Likes
Replies