How to mock #Inject Api-Class with Mockito - java

I'm trying to test a Java method with Junit,
Unfortunately I can't get any further at one point because the Api class was defended as #Inject
I actually tried everything I could, unfortunately null is always returned and the test fails every time.
#Inject
private MemberAPi memberApi;
NewMember newMember = new NewMember();
newMember = MemberApi.addMember(new CreateMemberParameterObj (newMember, getId , false, Obj ))
Test: I try to mock it like that e.g.
#Mock
private MemberAPi mockedMemberApi;
when(mockedMemberAPi.addMember(anyObject())).thenReturn(anyObject());

Mock the MemberAPI and the NewMember classes.
Use #InjectMocks and Mockito will automatically inject the mockMemberAPI object.
Here is some code:
#InjectMocks
private Blam classToTest; // your class.
#Mock
private MemberAPi mockMemberAPi;
#Mock
private NewMember mockNewMember;
#Before
public void before()
{
MockitoAnnotations.openMocks(this);
doReturn(mockNewMember).when(mockMemberAPI).addMember(anyObject());
}
I use the doReturn().when().xxx();
pattern instead of the
when(mockedMemberAPi.addMember(anyObject())).thenReturn(mockMemberAPI);
pattern.
Note:
thenReturn(anyObject()); makes no sense because you can't return anyObject().

Related

Unit Test: Cannot use ArgumentCaptor

I am trying to create a unit test for the following method that calls another private method:
public CommandDTO create(final LabelRequest request) {
return saveLabel(new Label(), request);
}
private CommandDTO saveLabel(final Label label, final LabelRequest request) {
label.setName(request.getName());
final Label saved = labelRepository.saveAndFlush(label);
return CommandDTO.builder().uuid(saved.getUuid()).build();
}
It returns "nullpointer exception for the saved parameter as I did not mock in in my test.
Here is the Unit Test. I added 2 question as comment (Q1 and Q2). Could you please clarify me what is wrong?
#RunWith(MockitoJUnitRunner.class)
public class LabelServiceImplTest {
#Mock
private LabelRepository labelRepository;
#InjectMocks
private LabelServiceImpl labelService;
#Captor
ArgumentCaptor<Label> labelCaptor;
#Test
public void test_create {
// Q1: I am not sure if the following parts are needed
final LabelRequest request = new LabelRequest();
request.setName("Label Name");
final Label label = new Label();
label.setName(request.getName());
// Q2: I think there is no need to mock saveAndFlush method.
// But in this scene it returns "nullpointer exception"
when(labelRepository.saveAndFlush(any())).thenReturn(label);
CommandDTO result = labelService.create(request);
Mockito.verify(labelRepository).saveAndFlush(labelCaptor.capture());
final Label value = labelCaptor.getValue();
// then make necessary assertions
}
}
F I R S T
I think that you only declared your mocks but never defined/created them. There's basically three ways to do so:
1) mockito extension
The convenient way in JUnit 5 is to use the MockitoExtension:
#ExtendWith(MockitoExtension.class)
public class LabelServiceImplTest {
// declare mocks, spies and captors ...
// system under test
#InjectMocks
LabelService sut;
}
Nothing else should be needed now.
Mind that by #InjectMocks you instruct Mockito to create your system under test and inject the mocks. You may as well do that manually, e. g. by injecting mocks into the SUT's constructor. I prefer that way to have more control over the configuration of my SUT.
2) MockitoAnnotations.openMocks(testclass)
This method will inject mocks into the given object:
public class LabelServiceImplTest {
// declare mocks, spies and captors ...
// system under test
#InjectMocks
LabelService sut;
#BeforeEach
void setup() {
MockitoAnnotations.openMock(this)
// ...
}
}
On JUnit 4 you'd use MockitoAnnotations.initMocks(…) instead.
3) the old school way
public class LabelServiceImplTest {
LabelRepository labelRepositoryMock = Mockito.mock(LabelRepository.class);
// ...
// system under test
LabelServiceImpl sut;
#BeforeEach
void setup() {
sut = new LabelService(labelRepositoryMock);
// ...
}
}
S E C O N D
Your questions …
1) Do you need to create the request and the label?
Yes. You call the service using the request and the mock returns the label. I would suggest you do not use the request's property to set up your label, use a String literal instead.
2) Do you need to mock the saveAndFlush() method?
Yes. This is the part where you configure your SUT's environment to behave in a predictable way.
You might consider postfixing your mocks, spies and captors by: "Mock", "Spy" and "Captor".
You might also consider calling your system under test "sut".
#Mock
private LabelRepository labelRepositoryMock;
#Captor
ArgumentCaptor<Label> labelCaptor;
// system under test
#InjectMocks
private LabelServiceImpl sut;
This makes the test code more readably, I think.

Mockito - Unmocked method failed to return the object itself

I have a Spring #RestController that has a field of Apache Camel interface FluentProducerTemplate.
I am testing the controller with MockMvc and I am injecting FluentProducerTemplate as a mock.
I would like to mock only one method - request(), and use the real implementation of the other methods.
However, I get NullPointerException from the unmocked methods. Other FluentProducerTemplate methods n , their return type is FluentProducerTemplate. In the implementation they return this. The mock object returns null.
I thought that mockito #Mock mocks only the methods that I specify. Other methods use the original implementation. Is this a correct statement?
I tried #Spy instead of #Mock and I got the same error.
When I mock all the methods that I work with then it works and no NullPointerException.
Code:
REST Controller:
#RestController
#RequestMapping("/v1/test”)
public class MyController {
#EndpointInject(uri = "direct:main")
private FluentProducerTemplate producerTemplate;
#RequestMapping(value = “/test2”, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public MyResponse testRequest(
#RequestHeader(“id”) String id,
#RequestHeader(“context”) String context,
#RequestBody RequestBody requestBody
) {
MyResponse response = producerTemplate
.withHeader(“id”, id)
.withHeader(“context”, context)
.withBody(requestBody)
.request(MyResponse.class);
return response;
}
Test:
#RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
private MockMvc mockMvc;
#Mock
private FluentProducerTemplate producerTemplateMock;
#InjectMocks
private MyControllerTest myController;
private static MyResponse expectedResultSuccess;
private static String requestString;
private static HttpHeaders allRequestHeaders;
#BeforeClass
public static void setup() {
allRequestHeaders = new HttpHeaders();
allRequestHeaders.set(“id”, “123”);
allRequestHeaders.set(“context”, “ABCD1234”);
allRequestHeaders.set(“Content-Type”, “application/json”);
expectedResultSuccess = new MyResponse(“test”);
requestString = “request”BodyText;
}
#Before
public void init() {
mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
}
#Test
public void testSuccess() throws Exception {
mockMvc.perform(post(“/v1/test/test2)
.headers(allRequestHeaders)
.content(requestString))
.andExpect(status().isOk())
}
}
The test pass only when I add the below to init():
when(producerTemplateMock.withHeader(any(), any())).thenReturn(producerTemplateMock);
when(producerTemplateMock.withBody(any())).thenReturn(producerTemplateMock);
My main question is - why do I have to mock all methods?
I prefer to use the original implementation of withHeader() and withBody() and mock only request().
You want so called partial mocks. Depending on whether you want to set up mostly mocks or mostly call real implementations there are different prefered approaches.
1. spy for few mocks, mostly real implementation
If you want to mock only some methods and otherwise call the real implementation:
FluentProducerTemplate producerTemplateMock = spy(FluentProducerTemplate.class);
// Mock implementation
doReturn(expectedResultSuccess).when(producerTemplateMock).request(any());
// All other method call will use the real implementations
2. mock for mostly mocks, few real implementations
FluentProducerTemplate producerTemplateMock = mock(FluentProducerTemplate.class);
// Mock methods
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);
// tell mockito to call the real methods
when(producerTemplateMock.withHeader(any(), any())).thenCallRealMethod;
when(producerTemplateMock.withBody(any())).thenCallRealMethod();
As you can see, the 2nd approach is more boilerplate to write. However, it depends on your use case what approach is better suited.

PowerMock static method mocking isn't taken into account for each #InjectMocks invocation

I want to write some unit tests, that use JUnit 4.12, Mockito 1.9.5 and PowerMock 1.6.1.
The class has some fields annotated with #Mock, as well as some fields annotated with #InjectMocks.
The attribute that is annotated with #InjectMocks reaches at some point a parent constructor which contains some static method invokation, that should be mocked with PowerMock.
The problem is the first test works seamlessly, while the second test does not seem to mock the static methods at all.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ StaticClass.class })
public class TestClass {
#Mock
private SomeClass attribute1;
#InjectMocks
private SomeOtherClass attribute2;
#BeforeClass
public static void setUp() {
PowerMockito.mockStatic(StaticClass.class);
when(StaticClass.staticMethod(any(), any()).thenReturn(new SomeConcreteClass());
}
#Test
public void test1() {
assertEquals(attribute2.method1(), value1);
}
#Test
public void test2() {
assertEquals(attribute2.method2(), value2);
}
}
public class SomeOtherClass {
private SomeClass attribute;
public SomeOtherClass() {
SomeConcreteClass value = StaticClass.staticMethod(argument1, argument2);
value.someOtherMethod();
}
}
As mentioned before, the first test passes and the StaticClass.staticMethod() is mocked as expected by PowerMock.
The second test does not pass and it throws a NullPointerException at line when someOtherMethod is called on value (because value = null, as the StaticClass.staticMethod was not mocked anymore by PowerMock).
As explained in (Mocking behaviour resets after each test with PowerMock) Powermock resets the mocks before each test.
For some reason it works the first time - there exists
an unresolved bug report for that issue (https://github.com/powermock/powermock/issues/398).
Its arguably bad design, but a way to do what you want is the following:
Instead of relying on the annotation set up the mocks manually.
private SomeClass attribute;
private SomeOtherClass testClass;
#Before
public void setUp() {
PowerMockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.staticMethod(anyString())).thenReturn(new SomeConcreteClass());
attribute = Mockito.mock(SomeClass.class);
testClass = new SomeOtherClass();
// assign mock manually
testClass.attribute = attribute;
}
The prefered way would be to supply the attribute using the constructor of SomeOtherClass, however since you seem to use a empty constructor
you will have to set the value from the outside. If the attribute instance is not accessible you might be forced to use reflections.
The cleaner way would be to refactor the constructor of you SomeOtherClass to not use a static method inside. Instead passing SomeConcreteClass as a parameter to the constructor is the way to go.
Some people even say you should not have any logic inside of a constructor.

Mockito: Java - Is it possible to Change a variable value used in an InjectMocks class?

I am wondering if this is possible. I have tried a few implementations using #mock and #spy to create a new string that has the same variable name as the one in a injectMocked class however I get the following error:
Cannot mock/spy class java.lang.String
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
In the class that is being used in InjectMocked I have:
public class Service{
String url = getUrl();
...
}
However I want to use a different url for testing as we have one for a testing environment.
I have tried things such as:
#Mock
private String url = "myUrlString";
#Spy
private String url = "myUrlString";
What I want is for when I run my Test the new value for url will be injected into the inJectMock and will be used instead of the other one.
Example:
#RunWith(MockitoJUnitRunner.class)
public class ServiceTest{
#Mock // or similar
private String url = "http://....";
#InjectMocks
private Service service = new Service();
}
So when the test runs the class is like this:
public class Service{
// Uses the inject url instead of the method that it originally uses
String url = "http://....";
...
}
Is this possible? If so how and if not how come? I can't be the only person to think to do this, however I cannot find any documentation on it.
You should just set the url with your test value, like service.setUrl(testUrl);. Mockito is not intended to provide mock values for variables, but to provide mocked implementations of methods you don't want to run in your unit tests.
For example if you have a class like this:
public class UrlProvider {
public String getUrl(){
return "http://real.url";
}
}
and you use it in your service:
public class Service{
UrlProvider provider;
public Service(UrlProvider provider){
this.provider = provider;
}
...
}
then you can easily change the returned value of the getUrl method:
#RunWith(MockitoJUnitRunner.class)
public class ServiceTest{
#Mock
private UrlProvider urlProvider;
#InjectMocks
private Service service = new Service();
#Before
public void init(){
when(urlProvider.getUrl()).thenReturn("http://test.url");
}
...
}

Null after #InjectMocks

I am having some troubles passing a dependency while unit testing with JUnit.
Consider these pieces of code:
This is the dependacy injecton into the class which i want to test, lets call it Controller.
#Inject private FastPowering fastPowering;
And this is the unit test:
#RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
#Mock
FastPowering fastPower;
#InjectMocks
Controller controller;
#Test
public void test() {
assertEquals(
(controller.computeAnswer(new BigDecimal(2), 2)).longValue(),
(long) Math.pow(2, 2));
}
}
It seems that fastPower is null, please explain how to fix that.
Null pointer exception , because of calling the #injected field (fastPower) inside the .computeAnswer method)
Edit:
Solved i should have read about the difference between #Mock and #Spy...
Due to a lot of comments I am adding some more context to the solution
The difference is that in mock, you are creating a complete mock or fake object while in spy, there is the real object and you just spying or stubbing specific methods of it. While in spy objects, of course, since it is a real method, when you are not stubbing the method, then it will call the real method behavior.
If fastPower is annotated as #Mock it's methods are dummy, yet controller.computeAnswer depends on them to compute. One must provide behaviour.
If spy is used without stubbing then the real implementation of fastPower is being executed which eventually returns desired value.
Another option is to use a real FastPowering instance
https://github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes)
https://github.com/mockito/mockito/wiki/Mocking-Object-Creation
And some stackoverflow thread outlining the difference Mocking vs. Spying in mocking frameworks
Short Answer: Replace #Mock with #Spy and should be working fine
Use MockitoAnnotations.initMocks to initiate the #Mock and #InjectMocks objects. Your test would look something like:
#Mock
FastPowering fastPower;
#InjectMocks
Controller controller;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
....
}
After debugging I found a reason. This is because of the org.powermock.core.MockRepository#instanceMocks collection. It doesn't contain a mock for a field with #InjectMocks annotation (Controller controller in your case).
To solve it try to use the #Spy annotation in the field declaration with initializing of them and #PrepareForTest above the class declaration:
#PrepareForTest(Controller.class)
#RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
#Mock
FastPowering fastPower;
#Spy
#InjectMocks
Controller controller = new Controller();
#Test
public void test() {
//...
}
}
In my case it helped. Using of the Mockitoannotations.initMocks(this) method is not required, it doesn't affect the result.
I fixed this by removing the extraneous new instance I was creating in my #Before method (see example below). It was also fixed by moving MockitoAnnotations.initMocks(this) after initializing myClass, but since Mockito created myClass anyway, that solution was inferior.
// Note - you may need #mock(name="foo") to help mockito differentiate props
// if they have the same type
#mock
private Thing something;
#InjectMocks
private MyClass myClass;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this); // Moving this below the next line fixed it...
myClass = new MyClass() // But just remove this line and let Mockito do the work
}
Useful to note that the use of MockitoAnnotations.initMocks(this); needs to come at the end of your #Before/setUp() method.
If it is at the top of your setUp() then it may cause other mocked classes to not be initialised.
I ran into this error myself just now and placing .initMocks at the end of my #Before solved my issue.
I was using the wrong #Test annotations, If you want to use #InjectMocks and #Mock in your Mockito Test, then you should
add #ExtendWith(MockitoExtension.class) annotation on your test class
annotate your test methods with #Test (org.junit.jupiter.api.Test) and not the #Test (org.junit.Test) annotation. be careful with the import that you are using for this annotation.
This works on mockito-core:3.6.28
2 more things to check:
1. Mocking the behaviours of fastPower. What should this mocked object return, when it methods are called? i.e. when(fastPower.doSomething()).thenReturn(some_kind_of_object);
2. Check if the controller.computeAnswer() does not return NULL for the input of new BigDecimal(2), 2)).longValue(), (long) Math.pow(2, 2).

Categories

Resources