How can I mock methods of #InjectMocks class? - java

For example I have handler:
#Component
public class MyHandler {
#AutoWired
private MyDependency myDependency;
public int someMethod() {
...
return anotherMethod();
}
public int anotherMethod() {...}
}
to testing it I want to write something like this:
#RunWith(MockitoJUnitRunner.class}
class MyHandlerTest {
#InjectMocks
private MyHandler myHandler;
#Mock
private MyDependency myDependency;
#Test
public void testSomeMethod() {
when(myHandler.anotherMethod()).thenReturn(1);
assertEquals(myHandler.someMethod() == 1);
}
}
But it actually calls anotherMethod() whenever I try to mock it. What should I do with myHandler to mock its methods?

First of all the reason for mocking MyHandler methods can be the following: we already test anotherMethod() and it has complex logic, so why do we need to test it again (like a part of someMethod()) if we can just verify that it's calling?
We can do it through:
#RunWith(MockitoJUnitRunner.class)
class MyHandlerTest {
#Spy
#InjectMocks
private MyHandler myHandler;
#Mock
private MyDependency myDependency;
#Test
public void testSomeMethod() {
doReturn(1).when(myHandler).anotherMethod();
assertEquals(myHandler.someMethod() == 1);
verify(myHandler, times(1)).anotherMethod();
}
}
Note: in case of 'spying' object we need to use doReturn instead of thenReturn(little explanation is here)

All answers above are really good and may be useful so make sure you study and understand these principes first before continue reading my post.
In my scenario none of advices above did work. I will post what helped me after a pretty long debugging.
If you want to call methods from tested class, the #Spy annotation is needed alongside #InjectMocks (or Mockito.spy(XXX) call or course)
The interesting part is, the order of these annotations does matter!
The #Spy annotation must precede #InjectMocks annotation.
Will not work
...
#InjectMocks
#Spy
private TestedObject instance
...
Will work
...
#Spy
#InjectMocks
private TestedObject instance
...

In your code, you are not testing MyHandler at all. You don't want to mock what you are testing, you want to call its actual methods. If MyHandler has dependencies, you mock them.
Something like this:
public interface MyDependency {
public int otherMethod();
}
public class MyHandler {
#AutoWired
private MyDependency myDependency;
public void someMethod() {
myDependency.otherMethod();
}
}
And in test:
private MyDependency mockDependency;
private MyHandler realHandler;
#Before
public void setup() {
mockDependency = Mockito.mock(MyDependency.class);
realHandler = new MyHandler();
realhandler.setDependency(mockDependency); //but you might Springify this
}
#Test
public void testSomeMethod() {
//specify behaviour of mock
when(mockDependency.otherMethod()).thenReturn(1);
//really call the method under test
realHandler.someMethod();
}
The point is to really call the method under test, but mock any dependencies they may have (e.g. calling method of other classes)
If those other classes are part of your application, then they'd have their own unit tests.
NOTE the above code could be shortened with more annotations, but I wanted to make it more explicit for the sake of explanation (and also I can't remember what the annotations are :) )

Related

How to avoid skipping methods of mock/spy

My target is to get inside the flow of spy method.
I mean, I don't want to skip "manager.createChange(processId);".
Actually, I want the test class will take me inside (and then I will do all mockito behavior changes..). For now, I can reach the flow until the method and then the method has been skipped.
I know the code logic may not correct, so please do not focus on that :)
Any help regarding how I suppose to design the test class in order to:
Use manager as a mock/spy (control mockito behavior).
Can be able to run his methods.
My test class:
#RunWith(SpringRunner.class)
public class createChangeTest {
#Mock
private ProcessRepository processRepository;
#Mock
private ProcessManager manager;
#InjectMocks
private RequestsImpl Requestsimpl;
Process p = new Process();
#Before
public void setUpBefore() {
ProcessManager manager = spy(new ProcessManager(processRepository));
}
#Test
public void changeRequestTest() {
Process p = Requestsimpl.createChange(11l);
}
inside Requestimpl:
#Named
#Transactional
#Component
public class RequestsImpl {
#Inject
private ProcessManager manager;
public Process createChange(Long processId) {
Process changeRequest = manager.createChange(processId);
return changeRequest;
}

Mockito when isn't replacing original method behaviour

I got 2 modules User and Email, both of them have 1 entry point which is a facade, rest is package scoped. The configuration is done in 2 classes
#Configuration
class UserConfiguration {
#Bean
UserFacade userFacade(UserRepository repository, EmailFacade emailFacade) {
return new UserFacade(repository, emailFacade);
}
}
#Configuration
class EmailConfiguration {
#Bean
EmailFacade emailFacade(EmailSender emailSender) {
return new EmailFacade(emailSender);
}
}
Now, I want to write tests that don't require Spring to start. I implemented a simple InMemoryRepository to make this happen
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade = new EmailFacade(new FakeEmailSender());
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I need some fake objects to instantiate EmailFacade so I wrote fake implementation
public class FakeEmailSender implements EmailSender {
#Override
public void sendEmail(EmailMessage emailMessage) throws RuntimeException {
}
}
In that scenario, I'm testing User domain, so I want to mock Email anyways.
I wrote a test to check if it works
#Test
public void shouldReturnSendingFailed() {
Mockito.when(emailFacade.sendUserVerificationEmail(Mockito.any())).thenReturn(Either.left(EmailError.SENDING_FAILED));
assertThat(userFacade.registerNewUser(RegisterUserDto.builder()
.username(USERNAME_4)
.email(VALID_EMAIL)
.password(VALID_PASSWORD).build()).getLeft(), is(EmailError.SENDING_FAILED));
}
But it isn't... after running this test I got
java.util.NoSuchElementException: getLeft() on Right
edit#
regiserNewUser() method
Either<DomainError, SuccessMessage> register(RegisterUserDto registerUserDto) {
if(userRepository.findUser(registerUserDto.getUsername()).isPresent())
return Either.left(UserError.USERNAME_ALREADY_EXISTS);
var userCreationResult = User.createUser(registerUserDto);
var savedUser = userCreationResult.map(this::saveUser);
var emailDto = savedUser.map(this::createVerificationEmail);
return emailDto.isRight() ? emailFacade.sendUserVerificationEmail(emailDto.get())
: Either.left(emailDto.getLeft());
}
Edit2#
With following test configuration
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I got nullpointer here, last line of registerNewUser().
Try running this code
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
private UserFacade userFacade;
#Before
public void setUp() {
userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
}
}
There are a few issues with your code:
You initialize your mocks twice. You don’t need to call initMocks in the setUp method if you are using Mockito runner
You are trying to inject mocks to already initialized object. But the field you are trying to inject is also passed to the constructor. Please read #InjectMocks doc, to check the strategies used to inject the mocks:
constructor (not used here, already initialized object)
setter (do you have one?)
field (is it not final)
There are details to each strategy (see my questions above). If no staregy is matched, Mockito will fail silently. The fact that you are passing an object in constructor, and rely on setter or field injection afterwards makes this code unnecesarily complex.

Use Mocked object in JUnit / Mockito test

I have a JUnit test that reads
public class EventHandlerTest {
#Mock
ThreadPoolExtendedExecutor threadPoolExtendedExecutor;
private EventHandler handler;
private Map<Queue<SenderTask>> subBuffers = new HashMap<>();
#Before
public void setUp() {
// PROBLEM: threadPoolExtendedExecutor null!
handler = new EventHandler(subBuffers, threadPoolExtendedExecutor);
}
}
When I call new in setUp, I have threadPoolExtendedExecutor=null.
I would like to insert some mocked threadPoolExtendedExecutor so, I do not have NullPointer problems when calling its methods (so simple interface mock is enough for me at this moment)
You can simply mock it using (in setUp)
threadPoolExtendedExecutor = mock(ThreadPoolExtendedExecutor.class);
#Before
public void setUp() {
threadPoolExtendedExecutor = mock(ThreadPoolExtendedExecutor.class);
handler = new EventHandler(subBuffers, threadPoolExtendedExecutor);
}
You can also let MockitoJUnitRunner do it for you :
don't forget to inject mocks in your service under test by annotating it with #InjectMocks
#RunWith(MockitoJUnitRunner.class)
public class EventHandlerTest {
#Mock
ThreadPoolExtendedExecutor threadPoolExtendedExecutor;
If you would like to use the #Mock or #InjectMocks annotations on the test class fields then you need to add #RunWith(MockitoJUnitRunner.class) at the class level.
#RunWith(MockitoJUnitRunner.class)
public class EventHandlerTest {
#Mock
ThreadPoolExtendedExecutor threadPoolExtendedExecutor;
Another approach is to not use the above annotations and manually create mocks by calling org.mockito.Mockito.mock().

Mocking subclass items with mockito in java

I have written a testclass for a baseclass that uses a factory. I #Mocked the factory to return a Mock object.
It looks sort of like this.
class BaseClass{
SomeFactory factory;
public BaseClass(SomeFactory factory){
this.factory=factory;
}
public void parse(){
factory.createSomething();
}
}
Now my (working) testclass looks like this.
#RunWith(MockitoJUnitRunner.class)
public class BaseTest {
#Mock
SomeFactory factory;
#Mock
SomeCreation crateation;
BaseClass subject;
#Before
public void setUp(){
when(factory.createSomething()).thenReturn(someCreation);
subject = new BaseClass(factory);
}
#Test
testParse(){
subject.Parse();
verify(factory).createSomething();
}
}
This all works fine, but now i have extended BaseClass (lets call it SubClass) and added some functionality. My SubClass also uses an extended factory (SubFactory). So i also want to extend BaseTest and run the same tests, because it does the exact same thing and something extra.
so i overrode the setUp() like so:
class SubTest extends BaseTest{
#Mock
SubFactory subFactory;
#Mock
Something something;
#Override
public void setUp(){
when(subFactory.createSomething()).thenReturn(
factory = subFactory;
subject = new SubClass(subFactory);
}
}
This however doesn't work, because in the baseclass it throws an UnfinishedVerificationException saying:
Missing method call for verify(mock) here:
pointing to the verify in the BaseClass.
Any ideas on how to structure my test-cases that allows me to test the SubClass with the same tests as BaseClass?
Thank you,
Do not extend test cases! Even though there will be (lots of) duplicated code, it's easier to be read and followed.
So, the subclass test should not extend the BaseClass test, but rather re-use the tests on the functionality, which will not be overwritten in the subclass. Also, a getter for the factory would be needed to better customize the behavior on the mocked factory:
class SubClass extends BaseClass {
SubClass(SubFactory factory) {
super(factory);
}
SubFactory getFactory() { return factory; }
public void parse() {
getFactory().createSomething();
}
}
class SubTest {
#Mock
SubFactory subFactory;
#Mock
Something something;
#Mock
SubCreation someSubCreation;
SubClass subject = new SubClass(subFactory);
public void setUp() {
when(subFactory.createSomething()).thenReturn(someSubCreation);
}
}

Mocked method is never getting called

I'm trying to write a test case for a java class. I've mocked a method using Mockito, but the mock is never being used. Why?
Below is the structure of my java class:
class A {
#Autowired
private ClassB classB;
publiv void methodOne() {
methodTwo();
}
private void methodTwo() {
...
int returnedValue = classB.someMethod();
...
}
}
The test class is given below:
class ATest {
#Mock
private ClassB classB;
#InjectMocks
#Autowired
ClassA classA;
#Before
public void setupTest() {
MockitoAnnotations.initMocks(this);
}
#Test(expected = SomeException.class)
public void testMethodOne() {
when(classB.someMethod()).thenReturn(29);
classA.methodOne();
}
}
The test class is extended from another which has the #RunWith(SpringJUnit4ClassRunner.class) annotation.
I've gone through the existing questions but have been unable to find an answer. If there is any question/answer that may help me, please point me to the same.
Thanks in advance!
You could try to remove #Autowired in your test class ATest.
#InjectMocks should be sufficient as it creates your test object and injects your mock.
Depending on your JUnit runner #Autowired might perform a second injection after #InjectMocks which overrides your mocked method setup.
First, a few notes on your test:
- the test should be public
- class A should be public
- there is no need for #Autowire in the test
- there is no need to call initMocks
Then, your test isn't actually testing if the mock is being used or not. Let's change these method so that they now return the value, so that we can test if they work or not:
public class ClassA {
#Autowired
private ClassB classB;
public int methodOne() {
return methodTwo();
}
private int methodTwo() {
return classB.someMethod();
}
}
public class ClassB {
public int someMethod() {
return 0;
}
}
We can now test:
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
private ClassB classB;
#InjectMocks
ClassA classA;
#Test
public void testMethodOne() {
when(classB.someMethod()).thenReturn(29);
final int result = classA.methodOne();
assertEquals(29, result);
}
}
And the test passes - meaning the mock is being used correctly.
Hope that helps.
What you're missing is that annotations are just declarations. The #Mock and #InjectMocks annotations don't do anything. They are only markers that can be seen by the test runner to perform specific runner-specific behavior. You need a #RunWith annotation to specify a test runner, but you need a specific test runner for specific behavior. If you're using the SpringJUnit4ClassRunner, then none of the Mockito annotations will be used. In any case, I wouldn't want to use the SpringJUnit4ClassRunner for unit tests, as you should just be verifying business logic, not wiring.
Change your test class to use #RunWith(MockitoJUnitRunner.class) and remove the base class reference.

Categories

Resources