I am using mockito to test mu jdk11-springboot application.
My application has class 'ClientRepository' and that has a method called 'findById' which takes a param of type UUID.
SO the method looks like :
public String findById(UUID id)
Now I mocked the class to test as :
#MockBean
private ClientRepository clientRepo;
Now I am trying to figure out how to pass the UUID param here:
Mockito.when(clientRepo.findById(UUID id))
.thenReturn(dslContext.selectFrom(CLIENT).where(CLIENT.ID.eq(UUID.fromString("3e064b19-ef76-4aea-bf82-e9d8d01daf1c"))).fetch());
Can anyone help?
You can use the following construction:
UUID expected = ...;
Mockito.when(clientRepo.findById(Mockito.eq(expected))).thenReturn(...);
This can be a good solution if the expected UUID is not the same instance that you configure in the test.
Another point to consider:
You seem to use JOOQ but have a mock bean for repository, which means that you probably test some kind of service (business logic layer).
In this case maybe you don’t need to work with database at all, just create a string and return in thenReturn part of the mocking configuration
Mockito.when(clientRepo.findById(Mockito.any(UUID.class))
.thenReturn(dslContext.selectFrom(CLIENT).where(CLIENT.ID.eq(UUID.fromString("3e064b19-ef76-4aea-bf82-e9d8d01daf1c"))).fetch());
Use Mockito.eq("your-uuid-goes-here") instead if your mock should only react to specific values.
Passing the value directly for which the mock is expected to return should also work.
Mockito.when(clientRepo.findById(<expected UUID>)
.thenReturn(dslContext.selectFrom(CLIENT).where(CLIENT.ID.eq(UUID.fromString("3e064b19-ef76-4aea-bf82-e9d8d01daf1c"))).fetch());
Related
I'm fairly new to Mocking, but I've read a lot, also took a course in udemy (not like I'm an expert, very far from it, just saying I've been studying this), but still, I cannot figure out something.
I have read this post Mockito - difference between doReturn() and when(), which made me understand a few things.
Now let me explain my problem.
I have a service impl class, that calls a repository class to get/do whatever I want. This service class is the one I'm writing my mockito's tests for.
This problem can be addressed in 2 different ways.
First way: (when thenReturn)
I have my test class which looks something like this (pseudo code):
serviceImplCastTest {
#Spy
#InjectMocks
ServiceImplClass serviceImplClass;
#Mock
RepositoryClass repositoryClass;
#Test
void whenMethodInService_thenReturnNonEmptyMap() {
List<Class> classList = new ArrayList<~>();
Class class = new Class("Whatever");
classList.Add(class)
Map<String, Class> classMap = classList.stream.collect(Collectors.toMap(Class::getMethod, Function.identity()));
when(serviceImplClass.methodInService()).thenReturn(classMap);
Map<String, Class> actualMap = serviceImplClass.methodInService();
assertFalse(actualMap.isEmpty());
verify(repositoryClass, times(1)).methodInRepository();
}
So, this doesn't work because the method in the service, which returns a map, calls a method in the repository that returns a List of Class and then my method in the service turns that list into a map, and for some reason, Mockito is expecting a List of Class, instead of a Map. I get the Mockito wrong type of return error.
(This code works perfectly if the service method just returns the same type of List that the repository returns.)
Second way: (doReturn when)
serviceImplCastTest {
#Spy
#InjectMocks
ServiceImplClass serviceImplClass;
#Mock
RepositoryClass repositoryClass;
#Test
void whenMethodInService_thenReturnNonEmptyMap() {
List<Class> classList = new ArrayList<~>();
Class class = new Class("Whatever");
classList.Add(class)
Map<String, Class> classMap = classList.stream.collect(Collectors.toMap(Class::getMethod, Function.identity()));
doReturn(classMap).when(serviceImplClass).methodInService();
Map<String, Class> actualMap = serviceImplClass.methodInService();
assertFalse(actualMap.isEmpty());
verify(repositoryClass, times(1)).methodInRepository();
}
Now, when using doReturn when, everything works fine, except the verify, repositoryClass.methodInRepository() doesn't get called, or at least is not spied properly or something, Mockito throws error "Wanted but not invoked".
So I'm not sure how to fix this on the Mockito side, because a simple way is to change logic, service return list instead of map, then change my application to receive list and map it over there, but this implies affecting logic, which I was forbidden to do so.
Also and I'm honestly interested on being able to mock this, because I have a few other equivalent cases, where my service class processes the list then turns it into something else, and mocking still expects a list to be returned.
How can I mock this? What is the correct approach?
You are making the same mistake in both of your code snippets, in that you're stubbing a method in the class that you're trying to test, instead of stubbing the method in the mocked class.
This means that you're effectively just testing the stubbing, not testing the class itself.
What you want to do is
Get rid of the Spy annotation - you don't need a spy for this.
Stub the method of the repository class, not the service class.
That way, you'll be testing that the service class calls the repository class correctly, and handles the response from the repository class correctly. But you'll also be circumventing the implementation of the repository class, which is the whole point of using a mock.
I'm trying to mock the following piece of code in my JUnit test
requestData = requestRepository.findByRequestId(requestId);
by doing
#Mock
RequestRepository requestRepository;
#Mock
RequestData requestData;
Mockito.when(requestRepository.findByRequestId(requestId)).thenReturn(requestData);
But instead of giving the mock object back, i'm getting null value.
What is the correct way to mock MongoDB repository methods.
When using SpringRunner based test, use #MockBean to declare mock of your context beans.
If you don't know about your request id value (it may be a dynamic value) on that case you can use Mock.any(<?>.class).
Example:
Mockito.when(requestRepository.findByRequestId(Long.class)).thenReturn(requestData);
The above example is only for requestId of type Long, if you need integer then you need to change the class to Integer.
In EasyMock, when using annotation #Mock
You can set the to which member of the target object the mock will be assigned, using fieldName
Example:
/*assign mock impl ONLY for myInterface2 member of tested object*/
#Mock(type= MockType.NICE, name="secondMember", fieldName = "myInterface2")
private MyInterfaceImpl myInterfaceMock; //step 1 for runner
This is very convenient as I don't need to create a special constructor to assign the internal members with mocked objects
Question:
Is there such thing for partial mocking as well?
Many Thanks!
No. #Mock can't create partial mocks (yet). You can request it as a feature request: https://github.com/easymock/easymock/issues
I have a scenario where I have to set a property of a mocked object as follows:
SlingHttpRequest slingHttpRequest= mock(SlingHttpRequest);
slingHttpRequest.setAttribute("search", someObject);
When I try to print this attribute I get null. How do I set this property?
You don't normally set properties on your mocked objects; instead, you do some specific thing when it's invoked.
when(slingHttpRequest.getAttribute("search")).thenReturn(someObject);
I'm afraid you're misusing your mock SlingHttpRequest.
Mockito requires you to wire up your mock's properties before you use them in your test scenarios, i.e.:
Mockito.when(slingHttpRequest.getAttribute("search")).thenReturn(new Attribute());
You cannot call the setAttribute(final Attribute a) method during the test like so:
slingHttpRequest.setAttribute(someObject);
If you do this, when the test runs, getAttribute() will return null.
Incidently, if the code you are unit testing is going to call a setter on your mock in this way, do not use a mock. Use a stub.
Mock object is not where you store data, it's for you to teach the behavior when its methods are invoked.
try this: https://www.google.com/search?q=mockito+example&oq=mockito+example&aqs=chrome..69i57j0l5.6790j0j7&sourceid=chrome&espv=210&es_sm=93&ie=UTF-8
I'm probable 7 years late for the party, but I still would like to contribute.
You CAN set class property using the Whitebox from powermock:
Whitebox.setInternalState(mockedClass, "internalField", "Value to be returned")
I have a scenario ,like i am creating i18n object instance dynamically in code. I am using the following code:
public String getLocaleString(Locale locale, SlingHttpServletRequest request){
final ResourceBundle bundle = request.getResourceBundle(locale);
I18n i18n = new I18n(bundle);
return i18n.get("local");
}
Here locale, request I have mocked. But i18n is created dynamically. so am not able to mock i18n.get("local").
I tried using:
when(any(I18n.class).get("local")).thenReturn("localizedString")
But I am not able to. I am getting NullPointerException in this line.
I would like to use Mockito for mocking this scenario. Can you guys help me please? Thanks.
Mockito has suggesting refactoring to get around this https://code.google.com/p/mockito/wiki/MockingObjectCreation?ts=1332544670&updated=MockingObjectCreation
I normally avoid testing internals of the method.
But in some cases when I really need I use PowerMockito https://code.google.com/p/powermock/wiki/MockConstructor
I don't think it's possible to use any() in that way, as it's an argument matcher, you should only specify a mock object with a method invocation, e.g.:
when(mock(i18n).get("local")).thenReturn("localizedString");
I think that might be the source of your NullPointerException.
But to solve your problem, I think you have two options:
The first is to use a factory to create the I18n object, and then mock the factory:
...
private I18nFactory factory;
...
public String getLocaleString(Locale locale, SlingHttpServletRequest request){
final ResourceBundle bundle = request.getResourceBundle(locale);
I18n i18n = factory.get(bundle);
return i18n.get("local");
}
Then in your test, set up the factory to produce the object you want:
// Mock I18n, locale, request etc...
final I18nFactory factory = mock(I18nFactory.class);
when(factory.get(bundle)).thenReturn(i81n);
// Assign 'factory' to your Controller(?)
controller.setI18nFactory(factory);
// act, assert etc...
The second approach is to set up the locale and request mocks/objects in such a way that new I18n(...) creates a valid object which meets your expectations.
On balance, I think I would prefer to use the second approach, especially so if I18n is a 3rd-party class. Although without more information on the aim of your test, this answer is somewhat speculative. Anyway, I hope this helps.