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
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 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 {
}
}
Im not new to mockito, but this time I found an interesting case during my work. I hope you can help me out with it.
I need to inject mock to change certain method behaviour during the test. The problem is, the bean structure is nested, and this bean is inside other beans, not accessible from test method. My code looks like this:
#Component
class TestedService {
#Autowired
NestedService nestedService;
}
#Component
class NestedService {
#Autowired
MoreNestedService moreNestedService;
}
#Component
class MoreNestedService {
#Autowired
NestedDao nestedDao;
}
#Component
class NestedDao {
public int method(){
//typical dao method, details omitted
};
}
So in my test I would like the call NestedDao.method to return mocked answer.
class Test {
#Mock
NestedDao nestedDao;
#InjectMocks
TestedService testedSevice;
#Test
void test() {
Mockito.when(nestedDao.method()).thenReturn(1);
//data preparation omitted
testedSevice.callNestedServiceThatCallsNestedDaoMethod();
//assertions omitted
}
}
I have tried to do a initMocks:
#BeforeMethod
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
Also to add annotation upon my test class:
#RunWith(MockitoJUnitRunner.class)
Always getting nullpointers or wrong answer from method (not mocked).
I guess it's this nested calls fault, making it impossible to mock this Dao.
Also Ive read that #InjectMocks only would work with setters or constructor injection, which im missing (just #Autowire on private fields), but it didn't worked when I tried.
Any guess what am I missing? ;)
You could use #MockBean instead of #Mock and #InjectionMock.
#RunWith(SpringRunner.class)
#SpringBootTest
class Test {
#MockBean
NestedDao nestedDao;
#Autowired
TestedService testedSevice;
#Test
void test() {
Mockito.when(nestedDao.method()).thenReturn(1);
//data preparation omitted
testedSevice.callNestedServiceThatCallsNestedDaoMethod();
//assertions omitted
}
}
It makes sense to me, you are so wrong,
why?
It's because you're testing TestedService and the interaction with NestedService, not with the Dao, the Dao interaction should be verified on the NestedService tests
Look this:
#Component
class TestedService {
#Autowired
NestedService nestedService;
String sayHello(String name){
String result = "hello" + nestedService.toUpperCase(name)
}
}
#Component
class NestedService {
#Autowired
MoreNestedService moreNestedService;
String toUpperCase(String name){
String nameWithDotAtTheEnd = moreNestedService.atDot(name);
return nameWithDotAtTheEnd.toUpperCase();
}
}
On your test:
class Test {
#Mock
NestedService nestedService;
#InjectMocks
TestedService testedSevice;
#Test
void test() {
Mockito.when(nestedService.toUpperCase("rene")).thenReturn("RENE.");
//data preparation omitted
Assert.assertEquals("hello RENE.", testedSevice.sayHello("rene"));
//assertions omitted
}
}
As you can see, you are assuming the dependencies of TestedService are working well, you only need to verify that hello is being added as prefix of the string,
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.
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.