Mockito instead of stubbing the method, is invoking the method - java

I am basically a new bee in using Mockito framework.
#Test
#SuppressWarnings("rawtypes")
public void testGetCaseDetailResponse() throws Exception {
HashMap requestM = new HashMap<String, String>();
requestM.put("transactionId", "******");
requestM.put("clientSystem", "URW");
requestM.put("loginId", "JUSTINN");
Mockito.when(caseDetailsService.getSAPCaseDetail(Mockito.any(), requestM))
.thenReturn(sapCaseDetailResponse);
}
the below part of the code which should ideally stub the method caseDetailsService.getSAPCaseDetail is invoking the method. I ran on debug mode and verified that is the case.
Mockito.when(caseDetailsService.getSAPCaseDetail(Mockito.any(), requestM))
.thenReturn(sapCaseDetailResponse);
For more info on the initialization part
#RunWith(MockitoJUnitRunner.class)
public class CaseDetailsServiceTest {
#Mock
RestTemplate restTemplate;
#Mock
AuthUtil authUtil;
#Mock
HttpHeaders httpHeaders;
#Mock
private HttpServletRequest httpRequest;
#Mock
SapServiceClient sapServiceClient;
#Mock
DateConvertUtils dateConvertUtils;
#Mock
CaseConverter caseConverter;
#InjectMocks
CaseDetailsService caseDetailsService;
I might be missing something, any help would be really appreciated, thanks in advance!

Here:
Mockito.when(caseDetailsService
But:
#InjectMocks
CaseDetailsService caseDetailsService;
The point of #InjectMocks is to insert previously created mock objects into an instance of your production class under test.
In other words: caseDetailsService isn't a mock. Thus you can't use when(caseDetailsService...).
You see, when() is used to specify the behavior of a Mockito created mock object. You can't apply when() on something that isn't a mock.
Thus, the real answer here: step back, and read a good tutorial about Mockito, and what its annotations really mean. Mocking frameworks are complicated, you can't learn them "trial and error"!
A good starting point: the tutorial at vogella.

Related

Getting NullPointerException tracer.currentSpan() is Null

I'm trying to create test case for given class and want to return traceId value but getting trace.currentSpan() is null.
Here is my Class
public class ConsumerService{
private final Tracer tracer;
#Autowired
private RequestService requestService;
public void consumerProductionRequest(DisclaimerRequest disclaimerRequest){
String traceId=tracer.currentSpan.context().traceId();
log.info(traceId);
if(disclaimerRequest.getReqId()==null){
disclaimerRequest.setReqId(UUID.randomUUID().toString());
}
}
}
//Test Class
#ExtendWith(MockitoExtension.class)
class ConsumerServiceTest{
#InjectMocks
ConsumerService consumerService;
#Autowired
Tracer tracer;
#Test
void Test(){
Tracer tracer=Mockito.mock(Tracer.class);
String traceId;
Mockito.when(tracer.currentSpan().context.traceId()).thenReturn(traceId);
DisclaimerRequest disclaimerRequest=new DisclaimerRequest();
consumerService.consumerProductionRequest(disclaimerRequest);
}
}
Why am I getting tracer.currentSpan() null. I'm using JUnit 5 and new in this. Please someone help me to solve this.
Here, in your test class:
#Autowired
Tracer tracer;
Turn that into
#Mock
Tracer tracer;
(and add the corresponding import to Mockito). You want that Mockito creates a mock object, and then inserts that into your object under test. Also note that your test method itself redefines tracer, thus shadowing whatever else you did on class level. Therefore that spec for tracer within the test method won't have any effect on the mocked Tracer instance that already got injected into your object under test.
Tracer tracer=Mockito.mock(Tracer.class);
String traceId;
Mockito.when(tracer.currentSpan().context.traceId()).thenReturn(traceId);
tracer will be mock and you can see it in debug or just simply print it.
also each method returns null because you didn't specify which method will return value because spring context does not work in unit tests. In integration tests you can autowire it.
Mockito.when(tracer.getCurrentSpan()).thenReturn(someSpan);
Mockito.when(tracer.getCurrentSpan().getContext()).thenReturn(someContext);
String traceId;
Mockito.when(tracer.currentSpan().context.traceId()).thenReturn(traceId);
You have to mock getCurrentSpan and getContext methods that will solve your problem. Also you can not autowire it just use #Mock annotation. Spring context does not exist in unit tests so it won't be autowired. Spring related codes won't work. Integration test runs the spring context for you and you can autowire it.

Mockito and Springboot: how best to mock (Mockito) only for specific tests?

I am experiencing problems while attempting to Mock a specific service, only for a specific test case.
I have tried the following:
#Mock
SomeService someService;
.
.
.
#Test
void getStatus_dunno() {
MockitoAnnotations.initMocks(this);
when(someService.getSomething("D11")).thenThrow(NumberFormatException.class);
assertEquals(HttpStatus.OK.value(),classUnderTest.getJobStatus("D11").getStatusCode().value());
}
The problem is that my Mock doesn't seem to take over. This is a #SprinBootTest, and I don't want to use #MockBean, as other tests in the same class require the real implementation.
Obviously, someService.getSomething(...) is called within my class under test.

How to inject mock for only one test case with Quarkus/RestAssured

I'm attempting to test a REST controller (using Quarkus) endpoint using rest assured. I want to mock a class that is injected into that controller (ideally with Mockio), but only for one of my tests. Or get different behaviour per test case without having to have separate classes for each test. I'm not sure how to do this?
I've seen doing it the way from the documentation:
#Mock
#ApplicationScoped
public class MockExternalService extends ExternalService {
#Override
public String service() {
return "mock";
}
}
But this would only allow me to use one mock for all tests and not mock certain behaviours based on tests as I would with Mockito. I think?
I've tried creating a mock and annotating it with #Mock
#Mock
public TableExtractorService tableExtractorServiceMock = Mockito.mock(TableExtractorService.class);;
but I still get my real implementation when I use it. I'm using a constructor annotated with #Inject in my Controller that takes the TableExtractorService.
For a bit more information my test using restassured looks like this:
InputPart filePart = Mockito.mock(InputPart.class);
Mockito.when(tableExtractorServiceMock.Extract(anyObject()))
.thenThrow(IOException.class);
final InputStream inputStream = filePart.getBody(InputStream.class, null);
given()
.multiPart("file", inputStream)
.when().post("/document")
.then()
.statusCode(500);
That endpoint calls the service class that I'm trying to mock, and I want that mock to return an exception.
It can't be done. Quarkus documentation explains the issue:-
Although this mechanism is fairly straightforward to use, it nonetheless suffers from a few problems:
A new class (or a new CDI producer method) needs to be used for each bean type that requires a mock. In a large application where a lot of mocks are needed, the amount of boilerplate code increases unacceptably.
There is no way for a mock to be used for certain tests only. This is due to the fact that beans that are annotated with #Mock are normal CDI beans (and are therefore used throughout the application). Depending on what needs to be tested, this can be very problematic.
There is a no out of the box integration with Mockito, which is the de-facto standard for mocking in Java applications. Users can certainly use Mockito (most commonly by using a CDI producer method), but there is boilerplate code involved.
Link for reference: https://quarkus.io/blog/mocking/
According Quarkus test documentation, you can do it usingo #QuarkusMock or #InjectMock.
As #Ankush said, a class annotated with the #Mock annotation is using the CDI #Alternative mechanism, and will be global. #QuarkusTestProfiles can be used to define CDI #Alternatives for groups of tests.
For example, instead of annotating the mock with #Mock, it could be referenced in a test profile as
default Set<Class<?>> getEnabledAlternatives() {
return Set.of(MyMockThing.class);
}
Any test annotatated with the
#TestProfile(MyMockyTestProfile.class)
profile would get those mocks, while others would use the original implementation.
What may be a simpler method is to just use #InjectMock. For example, in the test class, declaring a field like this:
#InjectMock
MyThing mock;
will ensure that mock is used by the classes under test, just for this test.
For rest clients, it will also be necessary to add a #RestClient annotation, and if the original implementation is a singleton, convertscopes can be used to coax the scopes into something mockable.
#RestClient
#InjectMock(convertScopes = true)
MyThing mock;
Behaviour can be added to the injected mock in #BeforeEach or #BeforeAll methods. For example
#BeforeEach
public void setup() {
when(mock.someMethod()).thenReturn("some value");
}

SpringBoot Container in Junit Test

I am unable to understand few things while testing with JUnit, I have written a few tests, while some seem to work simply with
#RunWith(MockitoJUnitRunner.class)
and
#Mock
some seem not to work with them, and so I have to use
#RunWith(SpringRunner.class)
and
#MockBean
I understand that #MockBean is used when dealing with Spring Container, while #Mock is just to use to replicate/mock a certain class and its methods. But what would be the perfect time to use #MockBean?
#Test
public void addBulkFcmLog() throws Exception {
JacksonTester.initFields(this, new ObjectMapper());
AdminFcmResource adminFcmResource = AdminFcmResource.builder()
.adminId(123L)
.build();
given(this.fcmService.addBulkFcmLog(any(BulkFcmDataResource.class))).willReturn(adminFcmResource);
MockHttpServletResponse response = mockMvc.perform(
post(Routes.SEND_FCM + "/admin/logs/add")
.contentType(MediaType.APPLICATION_JSON)
.content(bulkFcmDataResourceJacksonTester.write(BulkFcmDataResource.builder().adminId(123L).build()).getJson()))
.andExpect(status().isCreated())
.andReturn()
.getResponse();
assertThat(response.getContentAsString()).isEqualTo(
adminFcmResourceJacksonTester.write(adminFcmResource).getJson()
);
assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED.value());
}
Above is a test I wrote for a controller in my spring boot application, but When i mock the fcmService class using #Mock, the response comes with an empty body, but then I changed It to #MockBean and Autowired the controller class then test returned the right result.
How did this happen?
In an integration-test context it is always advisable to work with beans (mocked if necessary). Few points to keep in mind:
#MockBean takes care of injecting the object, you do not need to set it yourself.
If your configuration is wrong (you did not specify a #Qualifier for example), the test will expose that problem on startup.
In an integration test you want to have your system in a state which resembles the prod scenario as close as possible, and #MockBean gets you closer than a plain #Mock
Many times the bean dependencies have no setters and manual injection would be just plain hard.

Clarification about #Spy and #InjectMocks inside a #Service Spring Boot

Well, i am very confused about #Spy and #Mock. In my understand #Spy will call real methods and #Mock/#InjectMocks don't, because it just a mock, then i need a stub (when.thenReturn) if i would like to change the behavior of a mock.
In my test class i have this code:
#RunWith(MockitoJUnitRunner.class)
public class CaixaServiceTest {
#InjectMocks
private CaixaService caixaService;
#Mock
private CaixaRepository caixaRepository;
So, CaixaRepository is a JpaRepository interface from Spring Data and CaixaService just have a very simple method:
public void calcular(){
int a = (int) Math.pow(1,3);
log.info(a);
}
If i call caixaRepository.findOne(id) null should be returned because findOne is never called really, because it just a mock. This case works very well.
But when i call caixaService.calcular() the method body is executed (shouldn't because it is a mock), so log.info(a) is logged on my file.
I can't understand this behavior, because as i said in my understand #InjectMocks or #Mock shouldn't execute anything if stub not exists, this a #Spy task.
All is right but your understanding of #InjectMocks.
Indeed annotating a field with it will not create a mock object as you think.
Instead of, it will try to inject the mock dependencies to the object referenced by the field where the annotation is.
Note that this way of injecting the dependencies is not explicit and so doesn't document the dependencies to mock in your test.
Besides if the dependencies injection fails, Mockito will not report any failure.

Categories

Resources