Mockito test coming back as zero - spring

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.

Related

JUnit 5/Spring Boot - Use Properties but Mock Dependencies

I'm trying to write unit tests for a DAO/Repository. My intent is to mock the NamedParameterJdbcTemplate object within and verify that the surrounding business logic doesn't do any bad (i.e.: handles nulls, etc...).
I'd also like to verify that the SQL is combined correctly. I can do this with doAnswer(...), but the SQL queries live in a .properties file.
Is there a way to load a .properties file for testing, without loading all of the other dependencies of this class?
What I've Tried
I've tried decorating the Test class with various permutations of :
#ExtendWith(SpringExtension.class)
#ExtendWith(MockitoExtension.class)
#ContextConfiguration(classes = WidgetRepositoryImpl.class)
#TestPropertySource(properties = "sql.properties")
However, turning these on and off always seems to have one of the following effects:
Load the NamedParameterJdbcTemplate as a bean. This could work if I specified the nearby AppConfig class in the ContextConfiguration annotation, but then I'd need to load all of its underlying dependencies, and the whole point is to mock this field.
Load the Repository and mock the NamedParameterJdbcTemplate, but not load sql.properties. The SQL statements are now null.
I want to avoid ReflectionTestUtils.setField(widgetRepository, "namedParameterJdbcTemplate", "<put the sql here>"). This works, but there are many SQL queries (the code below is very simplified). It also introduces a risk of human error (since now we're testing strings in the Test class, not the actual properties file.
The question
Is there any way to load sql.properties for this class, but not attempt to load the NamedParameterJdbcTemplate?
Unit Test
#ExtendWith(SpringExtension.class)
#TestPropertySource(properties = "sql.properties")
class WidgetRepositoryImplTest {
#Mock
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Autowired
private WidgetRepository widgetRepository;
#Test
public void testGetWidgetById() {
// build a mock that returns a fake widget, and stores the SQL string for other tests
doAnswer(invocation -> { ...omitted for brevity... }).when(namedParameterJdbcTemplate).query(anyString(), anyMap(), any(WidgetMapper.class));
Widget widget = widgetRepository.getWidgetById("asdf-1234");
assertNotNull(widget);
}
Repository
#PropertySource("classpath:sql.properties")
#Slf4j
#Repository
public class WidgetRepositoryImpl implements WidgetRepository {
#Value("${widget-sql.selects.select-widget-by-id}")
private String selectWidgetByIdQuery;
#Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Override
public Widget getWidgetById(String id) {
Map<String, String> params = new HashMap<>();
params.put("widgetId", id);
List<Widget> results = namedParameterJdbcTemplate.query(selectWidgetByIdQuery, params, new WidgetMapper());
if (results.isEmpty()) {
return null;
}
return results.get(0);
}
sql.properties
widget-sql.selects.select-widget-by-id=select * from [WIDGETS] where WIDGET_ID=:widgetId
# a few dozen additional queries in here
The solution is to use SpringExtension with the #MockBean annotation. This annotation will generate a mock implementation of the given class and provide it as a Spring bean. This means that if your class uses #Autowired, Spring will inject the mock for you:
#ExtendWith(SpringExtension.class) // Make sure to use SpringExtension
#TestPropertySource(properties = "sql.properties")
class WidgetRepositoryImplTest {
#MockBean // Replace #Mock with #MockBean
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Autowired
private WidgetRepository widgetRepository;
// ...
}

mockito Call real methods

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());

How to test DaoImpl methods using Junit and Mockito

I am using spring with jdbcTemplate for my app and I want to test DaoImpl class. There is implementation for insertion, updation and retrieval operation
Dao class Method
//dummy class
public class PlayerDAOImpl implements PlayerDAO {
#Autowired
private JdbcTemplate jdbcTemplate;
public Integer getPlayer(int playerId) {
String sql = "SELECT ccount(1) FROM PLAYER WHERE
PLAYER_ID = ?";
return (jdbcTemplate. queryForObject("Query", new Object[]{playerId},
Integer.class)!=0); //here only throws exception
}
//other methods
}
and for that I have written Test class which execute successfully for insertion and updation but while retrieving it is giving nullpointer exception.
#RunWith(MockitoJUnitRunner.class)
class Test{
#InjectMocks
PlayerDAOImpl dao;
#Mock
JdbcTemplate jdbcTemplate;
#Test
public void retrieveResult(){
Mockito.when(dao.getPlayer(int playerId)).thenReturn(false);
//Assert Statement
}}
I have googled/tried but not found solution which worked for me. So how to test that method or inject jdbcTemplate so that it will succeed.
Thanks for Help!!
The problem is that you are trying to mock the class under test (PlayerDAOImpl) instead of its dependency (JdbcTemplate).
Change you mock to something like:
Mockito.when(jdbcTemplate.queryForObject(Mockito.any(), Mockito.any(), Mockito.any()).thenReturn(COUNT);
Where COUNT is an Integer, and then write your assertions on the return value of dao.getPlayer.

What is sense of #Mock annotation?

I have a question about bean creation in testing of controllers. For example, there is a such test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {MainApplicationConfiguration.class, JPAConfig.class})
#WebAppConfiguration
public class TestMainController {
private MockMvc mockMvc;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(mainController).build();
}
#InjectMocks
private MainController mainController;
#Mock
private EntryService entryService;
#Autowired
DBEntryRepository repository;
#Test
public void testEntryGet() throws Exception {
List<DBEntry> response_data = new ArrayList<>();
response_data.add(new DBEntry(1, 1, "STR", "DATE"));
Mockito.when(entryService.findAllEntries())
.thenReturn(response_data);
MvcResult result = mockMvc.perform(get("/VT/entry/"))
.andExpect(status().isOk()).andReturn();
verify(entryService, times(1)).findAllEntries();
verifyNoMoreInteractions(entryService);
}
}
and a controller method mapped on
/VT/entry/
#RequestMapping(value = "/entry/", method = RequestMethod.POST)
public ResponseEntity<Void> createEntry(#RequestBody DBEntry entry, UriComponentsBuilder ucBuilder) {
System.out.println("Creating entry " + entry.getNum());
try {
entryService.saveEntry(entry);
entryService.refreshEntryService();
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
}
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path("/entry/{id}").buildAndExpand(entry.getId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
EntryService is annotated with #Service annotation and MainApplicationConfiguration.class is a configuration with #EnableWebMvc and scan project for this EntryService.
by that I want to show that this controller really uses this EntryService in a real application and all are coupled by MainApplicationConfiguration.class.
Question is: Why entryService with #Mock annotation ended up in my controller code in the scope of my test execution? Shouldn't it be only for that instance only and inside of controller should be instantiated another bean(EntryService), why this annotation has mocked all occurrences of that bean (in the test scope)? I was thinking, that I should write whole other context web-context instead of MainApplicationConfiguration.class to mock it inside and substitute current definition. I am absolutely confused why this simple annotation have made such thing.
And if somebody can understand this magic, please say what is difference between #InjectMock and #Mock?
thanks for your attention! and sorry if my question is quite stupid. I am very new, it works, but I have not got magic yet.
In the documentation for #InjectMocks:
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order
So since EntryService is a dependency of your controller, #InjectMocks will try to find a mock object of EntryService in your test class and inject it into mainController.
Note that only one of constructor injection, setter injection, or property injection will occur.
#Mock marks the fields as mock objects.
#InjectMocks injects mock objects to the marked fields, but the marked fields are not mocks.

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