mockito Call real methods - spring-boot

I have this test:
but the method checkIfHold is also mocked
#RunWith(MockitoJUnitRunner.class)
public class FrontSecurityServiceTest {
#Mock
private FrontSecurityService frontSecurityService
= mock( FrontSecurityService.class, withSettings().defaultAnswer(CALLS_REAL_METHODS));
#Test
public void test1() {
when(frontSecurityService.getLoggedInUserId()).thenReturn("000");
frontSecurityService.checkIfHold(9L);
}
}
I also tried with
#Mock
PerService perService;
#Spy
private FrontSecurityService frontSecurityService = new FrontOfficeSecurityService(perService);
but then is not mocking the method getLoggedInUserId(), getLoggedInUserId is public, non-static, and non-final.
I also tried, there it works, but MenService is called inside checkIfHold is null
#RunWith(SpringJUnit4ClassRunner.class)
public class FrontSecurityServiceTest {
#Mock
MenService menService;
#Mock
FrontSecurityService frontSecurityService;
#Rule
public MockitoRule rule = MockitoJUnit.rule();
#Test
public void test1() {
MenReturn menReturn1 = MenReturn.builder().build();
when(menService.getMen(anyString(), anyLong())).thenReturn(Arrays.asList(menReturn1));
when(frontSecurityService.checkIfHold(anyLong())).thenCallRealMethod();
when(frontSecurityService.getLoggedInUserId()).thenReturn("000");
frontSecurityService.checkIfHold(9L);
}
}

I guess that #Spy is what you are looking for. Still, testing FrontSecurityService and also mock it at the same time seems odd to me.
Try the following:
#RunWith(MockitoJUnitRunner.class)
public class FrontSecurityServiceTest {
#Spy
private FrontSecurityService frontSecurityService;
#Test
public void test1() {
when(frontSecurityService.getLoggedInUserId()).thenReturn("000");
frontSecurityService.checkIfHold(9L);
}
}

Ideally, for FrontSecurityServiceTest, you should not be mocking FrontSecurityService. That's your system-under-test, and you don't want to test your mock, you want to test the system you're testing.
As in my other answer on Difference between Mockito #Spy and #Mock(answer = Answers.CALLS_REAL_METHODS), if you've mocked with CALLS_REAL_METHODS, then you're going to interact with your system (FrontSecurityService) where it has not run any constructors and has not initialized any fields. It is extremely unlikely that FrontSecurityService will work as expected like that.
As with João Dias's answer, #Spy is what you're looking for. As in the docs, you don't need to call the constructor explicitly, but only because #Spy is documented to do so for you. If you don't have a zero-arg constructor, #Spy will require you to call your constructor, so calling the constructor is not a bad habit to get into—especially if you're using a dependency injection framework or some other context where the constructor might gain parameters later. Your IDE doesn't understand Mockito and will not detect that the constructor is being called reflectively.
Once you have a #Spy, things should work as you expect—provided that getLoggedInUserId is public, non-static, and non-final.

The first issue I think is that you are using the #Mock annotation and also using Mockito.mock(...) at the same time.
You can mock an object, then tell Mockito which methods should execute the real implementation
Try the following:
#RunWith(MockitoJUnitRunner.class)
public class FrontSecurityServiceTest {
private FrontSecurityService frontSecurityService = Mockito.mock(FrontSecurityService.class);
#Test
public void test1() {
when(frontSecurityService.getLoggedInUserId()).thenReturn("000");
when(frontSecurityService.checkIfHold(Mockito.any())).thenCallRealMethod();
frontSecurityService.checkIfHold(9L);
}
}
If checkIfHold method returns void then you have to do something like the following:
Mockito.doCallRealMethod().when(frontSecurityService).checkIfHold(Mockito.any());

Related

Which is the right location for Mockito when(...).thenReturn(...) in JUnit5? The Test itself or #BeforeClass/#BeforeEach blocks?

Can anybody explain me if there is a difference between:
#SpringBootTest
public class MyServiceMockTest {
#Mock
private MyRepository myRepository;
#InjectMocks
private MyService myService = new MyServiceImpl();
#BeforeEach
void setMockOutput() {
when(myRepository.get(anyString())).thenReturn("something fetched");
}
#Test
void testGet() {
assertEquals("something fetched", myService.get());
}
}
and this:
#SpringBootTest
public class MyServiceMockTest {
#Mock
private MyRepository myRepository;
#InjectMocks
private MyService myService = new MyServiceImpl();
#Test
void testGet() {
when(myRepository.get()).thenReturn("something fetched");
assertEquals("something fetched", myService.get());
}
}
I understand, obviously that in the first case the when(...).thenReturn() will run before every test, while in the second only will run only once. But is that the only consideration?
Also, is there a point to make it run more than once? Should I do any clean up after each method?
The difference is that in the first example it will run before each test, so if instead of having only one test method you have multiple it will be execute before each of those. In your case I don't think it makes any difference.
The purpose is that if you wanted the same configuration to be the same for each test method of your class it would be easier having it in a BeforeEach instead of duplicating in each method.
You should do clean up only if needed, it's not something you always or never have to do, it depends from case to case.

Replace Mockito's when thenReturn implementation that was previously defined with new implementation

I am adding tests to a large codebase that is similar to this:
public class MyTests{
#Mock
private DBService dbService;
#Before
public void init(){
Mockito.when(dbService.getFromDb).thenReturn(getReturnResult());
}
}
Where getReturnResults() gets the some fake data. In 99% of cases this is the implementation I want, but when testing for exceptions I would like to do something like this:
#Test
public void useDifferentDBResults(){
Mockito.when(dbService.getFromDb).thenReturn(getDifferentReturnResult());
...
}
Where getDifferentReturnResult() gets some different data that will result in an error. I just need to replace the implementation for this one test.
Two things come to my mind:
Introduce in the same test class a second instance of DBService and use it "...when testing for exceptions":
#Mock
private DBService dbService;
#Mock
private DBService dbService2;
#Before
public void init() {
Mockito.when(dbService.getFromDb).thenReturn(getReturnResult());
Mockito.when(dbService2.getFromDb).thenReturn(getDifferentReturnResult());
}
...
#Test
public void useDifferentDBResults(){
// Use dbService2 here
...
}
or
Write a separate test class just for testing for exception(s) and move to that class useDifferentDBResults() and the respective test method(s).
If you want to dynamically provide the result of the mock then you could use the Answer interface of mockito. See this post for more details:
Dynamic return values with Mockito
Nevertheless I think in tests it is a best practice to repeat yourself in order to make each testmethod more readable. So my advice would be to move the mock initialization to each test method.

Mockito test coming back as zero

I am trying to get call method called totalmoney() to get the total money in the h2 database but it always returns 0.
#RunWith(MockitoJUnitRunner.class)
public class MoneyTests {
#InjectMocks
MoneyServiceImplementation MoneyServiceImplementation;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void getAllMoney() {
long total_money = MoneyServiceImplementation.TotalMoney();
assertEquals("2000", total_money);
}}
But it will return the right amount of 2000 by:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Bean.xml");
MoneyService MoneyService = (MoneyService) context.getBean("MoneyServiceImplementation");
long total_money = MoneyService.TotalMoney();
So what am i doing wrong in the test that it will not work?
Mockito is not an dependency injection framework, don't expect this shorthand utility to inject a complex graph of objectsbe it mocks/spies or real objects.
Again, note that #InjectMocks will only inject mocks/spies created using the #Spy or #Mock annotation.
There are no any #Mock or #Spy annotated beans in your test, so all of the dependencies in the created MoneyServiceImplementation are null.

MockBean stubbing ineffective

I have a configuration class with a few MockBeans replacing actual beans in context for tests.
#Configuration
public class MyTestConfig {
#MockBean
private MyService myService;
}
I use those mocks in my tests:
#Import({ MyTestConfig .class })
public class MyTest {
#Autowired
private MyService myService;
#Test
public void aTest() {
...
}
}
First the idea was to add the stubbing in this MyTestConfig configuration class, so that the mock is pre-made for all tests, so I did it in a #PostConstruct method, and it worked just fine - the mock in test did return the expected value:
#PostConstruct
public void init() {
when(myService.foo("say hello")).thenReturn("Hello world");
}
It turned out though, that constructing a pre-made mock suitable for all test can be tricky, so we decided to move the stubbing to tests.
#Test
public void aTest() {
when(myService.foo("say hello")).thenReturn("Hello world");
}
And this doesn't work - the stubbed method returns null. We want to leave MockBeans in the configuration class, but stub them in tests, so any advice on why the stubbing is ineffective?
Spring Boot 2.0.5, Mockito 2.22.0
Yes, stubbing should be performed inside their respective test cases (unless you have a test class that shares the stubbing scenarios but it all comes down to preference).
However, for creating #MockBeans, you would need to use a #SpringBootTest in order to get the actual beans replaced with mocks. This could be done as simply as this example:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTest {
#Autowired
private MyTestClass testClass;
#MockBean
private MyService service;
#Test
public void myTest() {
// testing....
}
}

Resetting Mockito mocks, provided as Spring beans, between tests?

I have a Java application that uses Spring's dependency injection. I want to mock out a bean, and verify that it receives certain method calls.
The problem is that Mockito does not reset the mock between tests, so I cannot correctly verify method calls on it.
My unit under test:
public class MyClass {
#Resource
SomeClientClass client;
public void myMethod() {
client.someMethod();
}
}
The unit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = UnitTestConfig.class)
public class MyClassTest {
#Resource
SomeClientClass client;
#Test
public void verifySomething() {
// ...
Mockito.verify(client).publish();
}
}
Finally,
#Configuration
public class UnitTestConfig {
#Bean
SomeClientClass client() {
return Mockito.mock(SomeClientClass.class);
}
}
Though I could hack my way around this problem by manually resetting mocks between tests, I wonder if there's a cleaner / more idiomatic approach.
I had to add this at the start:
#BeforeEach
void setup() {
Mockito.reset(...mockBeans);
...
}
Author not explained why he needs it, I can put more details.
Combining Spring's dependency injection with Mockito in this way not the best approach.
It leads to errors, because same Mocks will be reused between different tests!
This means that verify() will work incorrectly. It will accumulate method invocations from different tests. For example you will get "Wanted 1 time:" - "But was 2 times".
Most generic solution for this in Mockito is using #InjectMocks.
This annotation doing 2 important things:
actually injecting all #Mock fields into class annotated with #InjectMocks
resets each #Mock annotated class. (so, verify() will not accumulate invocations from different tests)
Code example:
#RunWith(MockitoJUnitRunner.class)
public class SomeSpringConverterTest {
#InjectMocks
private SomethingToJsonNodeSpringConverter someSpringConverter;
#Mock
private SomethingDatamodelService someDatamodelService;
#Test
public void convertOriginalContainerTest() {
SomethingContainer someContainer = buildSomeContainer("aa", "bb");
Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
Mockito.verify(someDatamodelService.getAttributes());
assertTrue(node.get("aa") != null);
}
#Test
public void convertOriginalContainerTest() {
SomethingContainer someContainer = buildSomeContainer("aa", "bb");
Mockito.when(someDatamodelService.getAttributes()).thenReturn(Arrays.asList("aa", "bb"));
JsonNode node = someSpringConverter.convert(someContainer, JsonNode.class);
Mockito.verify(someDatamodelService.getAttributes());
assertTrue(node.get("bb") != null);
}
}

Resources