-
Hi, The @Cacheable annotation is used in the following class: package org.soapservice;
import io.micronaut.cache.annotation.Cacheable;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import org.slf4j.Logger;
import org.soapservice.clients.SomeServiceClient;
import org.soapservice.v1.BusinessMethodRequestType;
import org.soapservice.v1.BusinessMethodResponseType;
import java.util.Locale;
@Singleton
public class CachedMessageSource implements MessageSource {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(CachedMessageSource.class);
final SomeServiceClient someServiceClient;
@Inject
public CachedMessageSource(SomeServiceClient someServiceClient) {
this.someServiceClient = someServiceClient;
}
@Cacheable(cacheNames = "my-cache")
@Override
public String getMessage(String code, Locale inputLocale) {
log.debug("code={}, inputLocale={}", code, inputLocale);
BusinessMethodRequestType request = new BusinessMethodRequestType();
request.setCode(code);
BusinessMethodResponseType codeValueResponseType = someServiceClient.businessMethod(request);
return codeValueResponseType.getPayload();
}
} The intent is that calls to the method getMessage() to be cached, in order to avoid calling "expensive" SOAP service (here mediated by SomeServiceClient). The Micronaut test class is: package org.soapservice;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.soapservice.clients.SomeServiceClient;
import org.soapservice.v1.BusinessMethodRequestType;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@MicronautTest
public class CachedMessageSourceTest {
private static final Logger log = org.slf4j.LoggerFactory.getLogger(CachedMessageSourceTest.class);
@Inject
CachedMessageSource cachedMessageSource;
@Inject
SomeServiceClient someServiceClient; //injected by MocksFactory
@BeforeEach
void setup() {
log.debug("Injected service ref: '{}'", someServiceClient);
}
/** the behavior of mock object is somehow not verified so this test
* fails at line 43
* */
@Test
void testCacheableAnnotation() throws ExecutionException {
String code = "aCode";
// First invocation with the same parameters should call the method.
String message = cachedMessageSource.getMessage(code, Locale.ENGLISH);
assertEquals("Payload for aCode", message, "should return the string set by the MocksFactory");
Mockito.verify(someServiceClient, Mockito.times(1)).businessMethod(any(BusinessMethodRequestType.class)); //line 43
// Second invocation with the same parameters should be cached and not call the method again.
message = cachedMessageSource.getMessage(code, Locale.ENGLISH);
Mockito.verify(someServiceClient, Mockito.times(1)).businessMethod(any(BusinessMethodRequestType.class));
// Change the parameters, and the method should be called again.
cachedMessageSource.getMessage("otherCode", Locale.FRENCH);
Mockito.verify(someServiceClient, Mockito.times(2)).businessMethod(any(BusinessMethodRequestType.class));
}
} The MocksFactory is a helper Factory bean declared under /src/test/java directory so that is visible only to the tests. It leverages the annotation @Replaces to replace the real implementation of the SomeServiceClient interface with the mock implementation supplied by Mockito. This behavior is triggered by a configuration flag, "mocks.enabled", read from the configuration file "application-test.yml". The test currently fails with error message:
The full source code is provided here: https://github.com/nedelva/mockitodemo What am I doing wrong? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Only after posting this question I realized the silly mistake I had made (as often happens 😞). The reason for test failure was that during testing two instances of SomeServiceClient were created: one used by CachedMessageSource and another one was created and injected in the test class CachedMessageSourceTest (field someServiceClient). The fix is trivial (once you know the cause of failure): the factory method MocksFactory.someServiceClient() needs to be annotated with @Singleton so that the same (mock) instance is used in all the injection points. D'oh! |
Beta Was this translation helpful? Give feedback.
Only after posting this question I realized the silly mistake I had made (as often happens 😞).
The reason for test failure was that during testing two instances of SomeServiceClient were created: one used by CachedMessageSource and another one was created and injected in the test class CachedMessageSourceTest (field someServiceClient).
The fix is trivial (once you know the cause of failure): the factory method MocksFactory.someServiceClient() needs to be annotated with @Singleton so that the same (mock) instance is used in all the injection points.
D'oh!