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.
Related
I'm using spring-boot-starter-test 2.2.0 which includes Mockito 3.1.0.
I would like to test this class:
#RestController
public class MyClass {
#Autowired MyAutowired myAutowired;
public int myClassMethod(int i) {
return myAutowired.methodToMock(i);
}
}
Which use this one:
#Service
public class MyAutowired {
public int methodToMock(int i) {
return i;
}
}
In my test I would like to run myClassMethod but with a mocked behavior for methodToMock. Ideally I would like to check if methodToMock was called with the expected argument.
Here is what I tried so far:
#SpringJUnitConfig(Config.class)
#WebAppConfiguration
#ExtendWith(MockitoExtension.class)
class MyClassTest {
#Autowired MyClass myClass;
#Mock
private MyAutowired myAutowired;
#BeforeEach
public void initMocks(){
MockitoAnnotations.initMocks(this);
}
#Test
public void myTest() {
Mockito.when(myAutowired.methodToMock(any()).thenReturn(1);
int shouldBe1ButIs2 = myClass.myClassMethod(2);
}
}
What's wrong with that ? And how to make myClass.myClassMethod(2) return 1 ?
The issue is that your object MyClass is not referring to the right mock instance. The MyAutowired has to injected into MyClass.
You have two options:
Creating a setMyAutowired method in MyClass and pass the MyAutowired instance to it in your test class.
Replacing #Autowired with #InjectMocks annotation on MyClass. In this way, an instance of MyClass will be created and mocks objects which you declared in your test will be injected automatically in it.
I normally use the second option, which is more elegant.
I am a beginner in Spring and I need to write test for this class if it calls methods:
class ClassOne {
#Autowired
AutowiredClass a1;
#Autowired
AutowiredClass a2;
void methodOne() {
a1.method1();
}
void methodTwo() {
a2.method2();
}
}
I've tried to write test, but failed, got NPE:
class ClassOneTest {
#Autowired
ClassOneInterface c1i;
#Test
public void testMethod1() {
c1i.methodOne(); // <- NPE appears here..
Mockito.verify(ClassOne.class, Mockito.times(1));
}
}
Would be great to successfully test void methods.
You can verify that using a unit test:
#RunWith(MockitoJUnitRunner.class)
public class MyLauncherTest {
#InjectMocks
private ClassOne c1 = new ClassOne();
#Mock
private AutowiredClass a1;
#Mock
private AutowiredClass a2;
#Test
public void methodOne() {
c1.methodOne(); // call the not mocked method
Mockito.verify(a1).method1(); //verify if the a1.method() is called inside the methodOne
}
}
ClassOne defines a spring bean. In order to Autowire the bean's fields you need a Spring Context.
If you want to test ClassOne as a SPRING BEAN, then you need to use SpringTest.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({MyConfig.class}) // Spring context config class
class ClassOneTest {
#Autowired
ClassOneInterface c1i;
...
}
A ClassOne bean will be injected into the test suite c1i field.
Then you can spy on the field using mockito:
ClassOne cSpy = spy(c1i);
Then you can verify method calls on it :
verify(cSpy).someMethod(someParam);
Hope this helps
You are getting a NPE because the loaded context on your test case cannot find the autowired bean you mentioned. You should annotate the test class like so:
#RunWith(SpringRunner.class)
#SpringBootTest
class ClassOneTest {
#Autowired
ClassOneInterface c1i;
#Test
public void testMethod1() {
c1i.methodOne(); // <- NPE appears here..
Mockito.verify(ClassOne.class, Mockito.times(1));
}
}
Consider taking a look at: Similar NPE test error
I want to write a kind of an integration test of a class and the "lower" classes that it calls during operation. I want to mock the database connection that is called by the "lower" class, but I have not found a way to do this.
I have a class, that calls another class, that calls the database through jdbcTemplate. I want to inject a mock jdbcTemplate to the lower class, but I seem to be injecting it to a wrong instance of the class. The code follows this template:
#Component
public class A {
#AutoWired
B b
public String someMethod() {
b.otherMethod();
}
}
#Component
public class B {
#AutoWired
jdbcTemplate jdbctemplate
public String otherMethod() {
jdbctemplate.query(args);
}
}
The test is like follows:
#RunWith(MockitoJUnitRunner.Silent.class)
public class aTestClass {
#Mock
JdbcTemplate jdbcTemplate;
#InjectMocks
B b;
#InjectMocks
A a;
#Test
public void aTest() {
a.someMethod();
}
}
But when I run this test I get a NullPointerException at a.someMethod() - it seems that the B-object being called is null.
The problem is, that if I mock B, then it's not ever going to actually call jdbcTemplate since it is a mock.
Can anybody shed some light on how I could inject a mock jdbcTemplate to a B-object that is being called by A?
If you want an actual integration test:
1) Don't mock the template.. mock the entire repository.
2) You don't need #InjectMocks in an integration test. Spring does the DI.
3) As this is IT test you would need to use SpringRunner.class, not the MockitoJUnitRunner.class runner.
#RunWith(SpringRunner.class)
public class aTestClass {
#MockBean
B b;
#Autowired
A a;
#Test
public void aTest() {
a.someMethod();
}
}
For a unit test just mock the B and inject on A:
#RunWith(MockitoJUnitRunner.Silent.class)
public class aTestClass {
#Mock
B b;
#InjectMocks
A a;
#Test
public void aTest() {
a.someMethod();
}
}
Do not mock dependencies of dependencies in a unit test. You should not care about lower levels there.
After DuckDuckGoing a bit I managed to get the test working with Maciejs instruction. At first it did not work, but adding #Configuration to both the beans it did. Here is the code that worked for me:
#RunWith(SpringRunner.class)
public class aTestClass {
#MockBean
JdbcTemplate jdbcTemplate;
#Autowired
B b;
#Autowired
A a;
#Test
public void aTest() {
when(jdbcTemplate.query(args)).thenAnswer(whatyouwant));
a.someMethod();
}
#Configuration
#Import(A.class)
static class AConfig {
}
#Configuration
#Import(B.class)
static class BConfig {
}
}
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 :) )
public interface Dummy {
public returnSomething doDummyWork(arg1, agr2);
}
public class A implements Dummy {
#AutoWired
PrintTaskExecutor printTaskExecutor;
public returnSomething doDummyWork(arg1, agr2) {
callingVoidMethod();
return something;
}
public void callingVoidMethod() {
printTaskExecutor.printSomething(arg1, arg2);
}
}
public class testDummy {
#Autowired
Dummy dummyA//this bean is configured in ApplicationContext.xml and it works fine.
#Mock
PrintTaskExecutor printaskExecutor;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
printaskExecutor = Mockito.mock(PrintTaskExecutor.class);
Mockito.doNothing().when(printaskExecutor).printSomething(anyString(), anyString());
}
#Test
Public void testA
{
Dummy.doDummyWork(arg1, arg2);//I m giving actual arguments
//instead of moocking it calls the original method.
Mockito.verify(printaskExecutor, times(1)).printSomething(anyString(), anyString());
}
}
I have an autowired TaskExecutor in the class I m testing and I want to mock it.I have tried this in my code and It calls the actual method instead of do nothing and in the verify it errors out saying no interactions happened. How should I handle this situation?
I try to avoid using Mockito and Bean Containers together in one test. There are solutions for that problem. If you use Spring you should use #RunWith(SpringJUnit4Runner.class). More on this subject: Injecting Mockito mocks into a Spring bean
The clean way: Actually your class testDummy does not test Dummy but A. So you can rewrite your class in following way:
public class testA {
#Mock
PrintTaskExecutor printTaskExecutor;
#InjectMocks
A dummyA;
...
BTW: #Mock together with initMocks(this) and printaskExecutor = Mockito.mock(PrintTaskExecutor.class); do the same, you can skip the latter statement.