Test EntityManager with JUnit and Mockito - java

I have tried to test the following class, but I have been unsuccessful.
#PersistenceContext
private EntityManager em;
#Transactional
public int sendToTableOne()
{
return em.createNativeQuery("INSERT INTO TABLE_ONE"
+ " SELECT * FROM TABLE_TWO")
.executeUpdate();
}
How can I test this class?
I'm using JUnit Jupiter on Spring framework.

I don't know if it's a good solution, but I obtain 100% coverage.
#Mock
EntityManager entityManager;
#Mock
Query query;
#InjectMocks
ThSwapDaoImpl daoImpl;
#BeforeEach
void setUp() throws Exception {
}
#Test
void test() {
when(entityManager.createNativeQuery(anyString())).thenReturn(query);
when(query.executeUpdate()).thenReturn(1);
assertEquals(daoImpl.sendToHistorical(), 1);
}

Related

Spring Boot #Before inserted data not available

I'm writing a simple authentication test with JUnit4 and TestContainers. Both my #Before and #After methods are #Transactional, but when I query for the data in UserDetailsServiceImpl it is not present and I can not figure out why. There is nothing async. Any ideas.
#Slf4j
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
#TestPropertySource(locations = "classpath:application-test.properties")
public abstract class DBEnabledTest {
#Autowired
protected EntityManager em;
#ClassRule
public static PostgreSQLContainer<?> sqlContainer = new PostgreSQLContainer<>("postgres:11")
.withDatabaseName("test_scenarios")
.withUsername("postgres")
.withPassword("postgres");
#BeforeClass
public static void setupEnv() {
System.setProperty("spring.datasource.url", sqlContainer.getJdbcUrl());
System.setProperty("spring.datasource.username", sqlContainer.getUsername());
System.setProperty("spring.datasource.password", sqlContainer.getPassword());
log.info("Running DB test with - " + sqlContainer.getJdbcUrl());
}
#After
#Transactional
public void truncateDb() {
List<String> tables = em.createNativeQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'").getResultList();
for (String table : tables) {
em.createNativeQuery("TRUNCATE TABLE " + table + " CASCADE").executeUpdate();
}
}
}
#AutoConfigureMockMvc
public class TestUserAuthentication extends DBEnabledTest {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private UserRepository userRepository;
#Before
#Transactional
public void initDBForEachTestMethod() {
User testUser = new User();
testUser.setEmail("test#user.com");
testUser.setPassword(new BCryptPasswordEncoder().encode("testUser1"));
testUser.setFirstName("Jonh");
testUser.setLastName("Dough");
testUser.setRole(AppRole.USER);
userRepository.saveAndFlush(testUser);
}
#Test
#Transactional
public void test_authenticationSuccess() throws Exception {
ResponseEntity<String> res =
restTemplate.postForEntity(
"/api/user/login",
JsonUtil.objectBuilder()
.put("email", "test#user.com")
.put("password", "testUser1")
.toString(),
String.class
);
assertTrue(res.getStatusCode().is2xxSuccessful());
String body = res.getBody();
JsonNode node = JsonUtil.nodeFromString(body);
assertNotNull(node.get("id"));
assertNotNull(node.get("token"));
assertNotNull(node.get("refreshToken"));
assertNotNull(node.get("expiresAt"));
DecodedJWT decodedJWT = JWTUtil.verifyToken(node.get("token").asText(), jwtConfig.getSecret());
assertEquals("test#user.com", decodedJWT.getSubject());
assertEquals(AppRole.USER, AppRole.valueOf(decodedJWT.getClaim(JWTUtil.ROLE_CLAIM).asString()));
}
}
#Component
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
com.concentric.scenarios.domain.user.User applicationUser = userRepository.findByEmail(email);
// data from #Before not available here !!!
if (applicationUser == null || applicationUser.isDeleted()) {
throw new UsernameNotFoundException(email);
}
if(applicationUser.getPassword() == null) {
throw new IllegalAccessError();
}
return new org.springframework.security.core.userdetails.User(email, applicationUser.getPassword(), new ArrayList<>());
}
}
That is because in the tests transactions get rolled back by default.
The section of the documentation describing this behaviour also describe how to change it if needed by using the #Commit annotation:
By default, the framework creates and rolls back a transaction for each test. [...]
If you want a transaction to commit (unusual, but occasionally useful when you want a particular test to populate or modify the database), you can tell the TestContext framework to cause the transaction to commit instead of roll back by using the #Commit annotation.

Data can't fetch from db - mockito

I am using the Mockito framework for my jUnit testing.
I am not able to fetch data from the database. Fetches null or empty from the db. Not sure how can I mock the entityManager.
public class AppServiceTest {
#Mock
private EntityManager entityManager;
#Mock
DataSource mockDataSource;
#Mock
Connection mockConn;
#Mock
PreparedStatement mockPreparedStmnt;
#Mock
ResultSet mockResultSet;
#Mock
private Query query;
#Test
public void testGetAllDc() throws NamingException {
AppDataService appDataService = Mockito.mock(AppDataService.class);
List<String> customResults = new ArrayList<String>();
//customResults = ....
System.out.println("**RESULTS**"+appDataService.getAllDc()); // here it is printed as []
Mockito.when(appDataService.getAllDc()).thenReturn(customResults);
}
}
AppDataService.java:
#Stateless
public class AppDataService{
#PersistenceContext
EntityManager entityManager;
public List<Object> getAllDc() {
try {
Query query = entityManager.createQuery("myQuery");
List<String> allDc= query.getResultList();
}
//......
}
Update:
Its observed that the mock values can be detected for entityManager as Mock for EntityManager, hashCode: 5425710. But entityManager.getCriteriaBuilder() or whatever entityManager.get....() are getting null in the AppDataService class .
In your test, you create a mock AppDataService appDataService = Mockito.mock(AppDataService.class);.
In order to test this class, you must not mock it. Either create it using new AppDataService() or let mockito do that for you (#InjectMocks)
To initialize the mocks or the class-under-test you may do this by using annotations and either use the mockito runner:
#RunWith(MockitoJunitRunner.class)
public class AppServiceTest {
#InjectMock
private AppService appService;
#Mock
private EntityManager entityManager;
or
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
Further, you mocked entitymanager, therefore all of it's methods are stubbed and return no values (null) per default on any method call.
If you expect the createQuery("myQuery") invocation to return something, you should stub it properly after mock creation/injection in the setup method.
#Before
public void setup() {
//...
when(entityManager.createQuery(eq("myQuery"))).thenReturn(query);
//OR
when(entityManager.createQuery(anyString())).thenReturn(query)
If it doesn't matter what the mocks return as long as it is not null, you may initialize the mocks using
#Mock(answer = Answers.RETURNS_DEEP_STUBS)) //OR #Mock(answer = Answers.RETURNS_MOCKS)
private EntityManager entityManager;
So the whole test should look like
#RunWith(MockitoJunitRunner.class)
public class AppServiceTest {
#Mock(answer = Answers.RETURNS_DEEP_STUBS))
private EntityManager entityManager;
#Mock
private Query query;
...
#InjectMocks
private AppDataService appDataService;
#Test
public void testGetAllDc() throws NamingException {
//arrange
List<String> customResults = new ArrayList<String>();
//TODO populate customResults
when(entityManager.createQuery("myQuery")).thenReturn(query);
when(query.getResultList()).thenReturn(customResults);
//act
System.out.println("**RESULTS**"+appDataService.getAllDc());
You don't need to mock appDataService if you want to test it. This field should be annotated with #InjectMocks.
#InjectMocks
private AppDataService appDataService = new AppDataService();
What you need to mock is entityManager.createQuery and query.getResultList methods.
Query queryMock = mock(Query.class);
when(entityManager.createQuery(anyString())).thenReturn(queryMock);
when(query.getResultList()).thenReturn(customResults);
After taht you can call appDataService.getAllDc() in your test and check the results.

Mock: when() requires an argument which has to be 'a method call on a mock'

I am writing the unit tests for my REST-API and have some problems with the entities creation mocking. I don't know how can I mock the EntityManager. I tried the example below but I got an error.
My ControllerTest:
public class MControllerTest {
private MockMvc mockMvc;
#InjectMocks A a;
#InjectMocks B b;
#InjectMocks AController aController;
#InjectMocks private AServiceImpl aServiceImpl;
#Autowired WebApplicationContext webApplicationContext;
#Autowired private FilterChainProxy springSecurityFilterChain;
#Autowired
#InjectMocks
private EntityManagerFactory entityManagerFactory;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(springSecurityFilterChain)
.build();
}
#Test
public void postATest() throws Exception {
a.setDDDD("XXX");
EntityManagerFactory entityManagerFactory = webApplicationContext.getBean(EntityManagerFactory.class);
EntityManager entityManager = entityManagerFactory.createEntityManager();
when(this.entityManagerFactory.createEntityManager()).thenReturn(entityManager);
when(aServiceImpl.createEntity(isA(A.class))).thenReturn(a);
b.setCCCC;
a.setMovieTranslations(Arrays.asList(b));
when(aServiceImpl.createEntity(isA(B.class))).thenReturn(a);
mockMvc.perform(post("/path")
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
}
The createEntityMethod:
public Object createEntity(T t) {
try {
entityManager.persist(t);
return t;
} catch (IllegalArgumentException | EntityExistsException | ...
}
The error log:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
at com.x.server.controller.MControllerTest.postATest(MControllerTest.java:121)
When I don't inject a mock object on the EntityManager, I got a nullpointer exception by the persist method with this error log:
java.lang.NullPointerException: null
at com.x.server.serviceImpl.AManageServiceImpl.createEntity(AManageServiceImpl.java:45)
at com.eza.server.controller.MControllerTest.postATest(MControllerTest.java:123)
Can someone help me?
Solve it. I just removed some line of code with the entitymanager interface and it works.
public class MControllerTest {
private MockMvc mockMvc;
#InjectMocks A a;
#InjectMocks B b;
#InjectMocks AController aController;
#Autowired WebApplicationContext webApplicationContext;
#Autowired private FilterChainProxy springSecurityFilterChain;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilter(springSecurityFilterChain)
.build();
}
#Test
public void postMovieTest() throws Exception {
a.setDDDD("XXX");
b.setCCCC;
a.setMList(Arrays.asList(b));
mockMvc.perform(post("/path")
.content(asJsonString(a))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.andExpect(status().isOk())
.andReturn().getResponse().getContentAsString();
}
asJsonString is by me self write method to convert object in json
Cheers

Spring data repository not injecting with #Mock in test case class returns null?

Repository object not injecting in testcase class.
Here is my below test class code
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classesExternalProviderMain.class)
#ActiveProfiles(ApplicationConstants.DEVELOPMENT_PROFILE)
#WebAppConfiguration
public class EmployeeServiceTest {
#InjectMocks
EmployeeService employeeService; //not injected null
#Mock
EmployeeRepository employeeRepository;//not injected null
#Test
public void testEmployee() {
Mockito.when(employeeRepository.findByName(Stringname)).thenReturn(getEmployee());
List<Employee> resultedTrackbles = employeeService.getEmployeeByName("mike");
}
private List<Employee> getEmployee(){
//here is the logic to return List<Employees>
}
}
Can you please help me how to inject my "EmployeeRepository" and Do need to write any additional logic.
That's because you are running your test with SpringJUnit4ClassRunner and not with MockitoJUnitRunner.
The mocks need to be initialized with MockitoAnnotations.initMocks:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}

With Spring, #InjectMock annotated test target doesn't use mocks

I'm trying to unit test a Spring 4.0.0 MVC application.
My controller is defined as follow:
#Controller
#RequestMapping("/test")
public class TestCtrl {
#Autowired
private TestService testService;
#Autowired
private TestRessourceAssembler testRessourceAssembler;
#Autowired
private ResponseComposer responseComposer;
#RequestMapping(value = "", method = RequestMethod.GET,produces = "application/json")
public HttpEntity showAll(Pageable pageable) {
Page<Test> patr = testService.getAll(pageable);
return responseComposer.composePage(patr,testRessourceAssembler);
}
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
public HttpEntity<TestRessource> show(#PathVariable String name) {
Test test = testService.getOne(name);
if(test == null){
return new ResponseEntity("Erreur !",HttpStatus.NOT_FOUND);
}
return responseComposer.compose(test,testRessourceAssembler);
}
}
My controller unit test is as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
#WebAppConfiguration
#ContextConfiguration(classes = {ApplicationConfig.class, TestMongoConfig.class, RestConfig.class, WebMvcConfig.class})
public class TestCtrlTests{
#InjectMocks
TestCtrl testCtrl;
#Mock
TestService testService;
#Autowired
protected WebApplicationContext wac;
protected MockMvc mockMvc;
#Before
public void setup(){
MockitoAnnotations.initMocks(this);
when(testService.getOne("jexiste")).thenReturn(new com.thalesgroup.ito.c2s.mc.portail.test.domain.Test("jexiste",1990));
when(testService.getOne("plaf")).thenReturn(null);
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void simpleGetAnswer() throws Exception{
assertNotNull(mockMvc);
mockMvc.perform(get("/test")).andExpect(status().isOk());
mockMvc.perform(get("/test/jexiste")).andExpect(status().isOk());
mockMvc.perform(get("/test/plaf")).andExpect(status().isNotFound());
}
}
When I'm running the test, the "normal" TestService bean is injected and used (I can see the trace in the log), not the mock.
So I read some things on the internet and replaced
this.mockMvc = webAppContextSetup(this.wac).build();
with
this.mockMvc = standaloneSetup(TestCtrl.class).build();
But, and I knew it would happen, I've no more Spring context when doing this, so my PageableArgumentResolver and my other beans (testRessourceAssembler, responseComposer) aren't injected anymore... So they are Null and happen a NullPointerException.
My question is:
1) I'm I designing something wrong ?
2) If not, how can I inject a mock in my controller while keeping other beans from the context ?
Thanks to you !
I'm looked into your tests and this should work. Simply build your MockMvc on your controller with mocked beans. After this all mocks will be visible inside test.
A MockMvcBuilder that accepts #Controller registrations thus allowing full control over the instantiation and the initialization of controllers and their dependencies similar to plain unit tests, and also making it possible to test one controller at a time.
Don't use Spring Integration test! This is simple unit testing!
Fixed test
#RunWith(MockitoJUnitRunner.class)
public class TestCtrlTests{
#InjectMocks
TestCtrl testCtrl;
#Mock
TestService testService;
protected MockMvc mockMvc;
#Before
public void setup(){
when(testService.getOne("jexiste")).thenReturn(new com.thalesgroup.ito.c2s.mc.portail.test.domain.Test("jexiste",1990));
when(testService.getOne("plaf")).thenReturn(null);
this.mockMvc = standaloneSetup(testCtrl).build();
}
#Test
public void simpleGetAnswer() throws Exception{
assertNotNull(mockMvc);
mockMvc.perform(get("/test")).andExpect(status().isOk());
mockMvc.perform(get("/test/jexiste")).andExpect(status().isOk());
mockMvc.perform(get("/test/plaf")).andExpect(status().isNotFound());
}
}

Categories