I have a class A, it has a dependency on a repository (maybe JPA repository).
Class A{
#Autowired
SomeRepository somerepository;
public int methodA() {
somerepository.findAll();
methodB();
}
public methodB() {
//do something
}
}
Now I want to write a test code that will mock the public methodB() and return some default value when its called. This can be done by mocking the ClassA bean.
Also I want to mock the repository so that when the repository findAll() method is called then some default value is returned ie mock repository and inject it into the ClassA bean.
Is there any way to fulfill both conditions?
Thanks in Advance !!
You can use spy type for this.
A a = Mockito.spy(new A());
you can mock the method below:
when(a.methodB()).thenReturn(XXX);
or
doNothing().when(a).methodB();
You can use #Spy for partial mocking(method B) and #InjectMocks to inject your mocked repository into your Class, something like this will work:
RunWith(MockitoJUnitRunner.class)
public class SpringDemoTest
{
#InjectMocks
#Spy
ClassA classA;
#Mock
SomeRepository someRepository;
#Test
public void testMethodA()
{
MockitoAnnotations.initMocks(this.getClass());
Mockito.when(classA.methodB()).thenReturn(50);
Mockito.when(someRepository.findAll()).thenReturn("This is a Mock!");
Assert.assertEquals("This is a Mock!", classA.methodA());
}
}
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 {
}
}
I am beginner with Mockito framework, and i have some problems in determining the mocked and injected mocks objects, Actually I have the following structure in my project.
//WebService Interface
Interface WebService{
#Gateway(...)
public x call1(parameters);
}
//Class that implements another interface
Class A implements interfaceA{
#Autowired
WebService WS;
public void M1(){
.....
WS.call1(parameters);
.....
}
}
//Test Class
#Mock
#Autowired
WebService WS;
#InjectMock
#Autowired
A a;
#Before
setup(){
MockitoAnnotations.initMocks(this);
}
#Test
#Rollback(true)
#Transactional
public void Test() {
when(WS.call1(parameters)).thenReturn(x);
actualResult = a.M1();
assertNotNull(actualResult);
verify(WS, Mockito.times(1)).call1(parameters);
}
Are the Mocked and injected mock objects chosen correctly?
And if yes, i keep getting this exception message:
Wanted but not invoked:
WS.call1(
........
);
Actually, there were zero interactions with this mock.
You are using #Mock and #Autowired together. This doesn't make sense. You either mock or autowire your beans. Remove Autowiring
#Mock
WebService WS;
#InjectMock
A a;
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.
I have Test class for controller. I need to inject autowired field. And mock method of Controller's super class (I have no possibility to refactor this situation)
public class ControllerTest {
#Mock
Service service;
#InjectMocks
Controller controller;
#Test
public vois test() {
controller.process();
}
}
In process() method service is called and superclass's method, too.
I tried to init my controller in test in this way
new Controller() {
#Override
superMethod() {
//do nothing
}
}
But I cannot inject service mock in this case due to setter is missing. I can do it with reflection, but maybe someone knows more elegant solution?
If you are using annotations, you must to put #RunWith(MockitoJUnitRunner.class) above the ControllerTest or create setUp method like this:
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
Hope this help.