Spring + Hibernate + TestNG + Mocking nothing persist, nothing is readed in test - spring

Fighting with TestNG, Spring an Hibernate. I'm writing test for Service class, and it's always failure. But without test class works fine. So App is working, but tests don't want to.
Here is my test class
#Transactional
public class BorrowerServiceTest {
#Mock
BorrowerDAOImpl borrowerDAO;
#InjectMocks
BorrowerService borrowerService;
#BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void persistTest() {
Borrower borrower = new Borrower.BorrowerBuilder().firstName("Lars").lastName("Urlich").adress("LA")
.phoneNumber("900900990").build();
borrowerService.persist(borrower);
List<Borrower> borrowerList = borrowerService.getBorrowerByName("Lars Urlich");
Assert.assertEquals(true, borrower.equals(borrowerList.get(0)));
}
}
My BorrowerService:
#Service("borrowerService")
#Transactional
public class BorrowerService {
#Autowired
private BorrowerDAO borrowerDAO;
public List<Borrower> getBorrowers() {
return borrowerDAO.getBorrowers();
}
public List<Borrower> getBorrowerByName(String name) {
return borrowerDAO.getBorrowerByName(name);
}
public boolean removeBorrower(Borrower borrower) {
return borrowerDAO.removeBorrower(borrower);
}
public boolean persist(Borrower borrower) {
return borrowerDAO.persist(borrower);
}
}
My BorrowerDAOImpl:
#Repository("borrowerDAO")
#Transactional
public class BorrowerDAOImpl extends DAO implements BorrowerDAO {
#Override
public List<Borrower> getBorrowers() {
List<Borrower> borrowerList = null;
Query query = entityManager.createQuery("SELECT B FROM Borrower B");
borrowerList = query.getResultList();
return borrowerList;
}
#Override
public List<Borrower> getBorrowerByName(String name) {
List<Borrower> borrowerList = null;
String[] values = name.split(" ");
Query query = entityManager.createQuery("SELECT B FROM Borrower B WHERE B.firstName LIKE '" + values[0]
+ "' AND B.lastName LIKE '" + values[1] + "'");
borrowerList = query.getResultList();
return borrowerList;
}
#Override
public boolean removeBorrower(Borrower borrower) {
String firstName = borrower.getFirstName();
String lastName = borrower.getLastName();
Query query = entityManager
.createQuery("DELETE Borrower where FIRST_NAME LIKE :FirstName AND LAST_NAME LIKE :LastName");
query.setParameter("FirstName", firstName);
query.setParameter("LastName", lastName);
query.executeUpdate();
return true;
}
#Override
public boolean persist(Borrower borrower) {
entityManager.persist(borrower);
return true;
}
}
and abstract DAO:
#Repository
#Transactional
public abstract class DAO {
#PersistenceContext
protected EntityManager entityManager;
}
Maven returns failure:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.get(LinkedList.java:476)
at com.me.service.test.BorrowerServiceTest.persistTest(BorrowerServiceTest.java:41)

I also had to fight with this. The problem here is that your test runs in it's own transaction, so nothing will be committed during method's execution. Now here is what I did:
public class IntegrationTest extends SomeTestBase
{
#Autowired
private PlatformTransactionManager platformTransactionManager;
private TransactionTemplate transactionTemplate;
#Autowired
private BeanToTest beanToTest;
#Override
#Before
public void setup()
{
super.setup();
this.transactionTemplate = new TransactionTemplate(this.platformTransactionManager);
}
#Test
public void fooTest()
{
// given
// when
boolean result = this.transactionTemplate.execute(new TransactionCallback<Boolean>()
{
#Override
public Boolean doInTransaction(TransactionStatus status)
{
return IntegrationTest.this.beanToTest.foo();
}
});
// then
}
}
This allows you to have methods execute within a separate transaction. Please note that you might declare some variables as final.
Hope that helps.

Check the Spring documentation: it looks your test class should extend AbstractTestNGSpringContextTests.

Use #Commit annotation on the whole test class or even method to persist changes made in the test. For more information https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#commit

Related

Unit testing using jUnit5 and mockito

Hi Im having troubles with my saveStudent method I can't seem to make the test work. What my saveStudent method do is when I add a student it automatically adds the fixed subjects from the database to the student. Can anyone explain to me what Im doing wrong in the testing and how to test this kind of method. Gladly appreciate it. Thank you for the answer!
Here is my TestService and my ServiceImplimentation
#ExtendWith(MockitoExtension.class)
public class StudentServiceTest {
#Mock
private StudentRepository studentRepository;
#Mock
private SubjectRepository subjectRepository;
#InjectMocks
private StudentServiceImpl studentService;
private Student student;
private List<Subject> subject;
// private List<Subject> subjectList;
private Collection<Remark> remarks = new ArrayList<>();
#BeforeEach
public void setup() {
student = new Student(1L, "Martin", 6, remarks);
subject = Arrays.asList(
new Subject(1L, "Math", remarks),
new Subject(2L, "English", remarks));
}
// JUnit test for saveStudent method
#DisplayName("JUnit test for saveStudent method")
#Test
public void givenStudentObject_whenSaveStudent_thenReturnStudentObject() {
given(subjectRepository.findAll()).willReturn(subject);
System.out.println(subject);
given(studentRepository.save(student)).willReturn(student);
System.out.println(studentRepository);
System.out.println(studentService);
Student savedStudent = studentService.saveStudent(student);
System.out.println(savedStudent);
assertThat(savedStudent).isNotNull();
}
// JUnit test for getStudentList method
#DisplayName("JUnit test for getStudentList method")
#Test
public void givenStudentsList_whenGetAllStudents_thenReturnStudentsList() {
Student student1 = new Student(1L, "Edmark", 4, remarks);
given(studentRepository.findAll()).willReturn(Arrays.asList(student, student1));
List<Student> studentList = studentService.findAll();
assertThat(studentList).isNotNull();
assertThat(studentList.size()).isEqualTo(2);
}
// JUnit test for getStudentById method
#DisplayName("JUnit test for getStudentById method")
#Test
public void givenStudentId_whenGetStudentId_thenReturnStudentObject() {
given(studentRepository.findById(1L)).willReturn(Optional.of(student));
Student savedStudent = studentService.findById(student.getStudentId());
assertThat(savedStudent).isNotNull();
}
// JUnit test for updateStudent method
#DisplayName("JUnit test for updateStudent method")
#Test
public void givenStudentObject_whenUpdateStudent_thenReturnUpdatedStudent() {
given(studentRepository.findById(1L)).willReturn(Optional.of(student));
given(studentRepository.save(student)).willReturn(student);
student.setStudentGrade(8);
student.setStudentName("Mark");
Student updatedStudent = studentService.updateStudent(1L, student);
assertThat(updatedStudent.getStudentName()).isEqualTo("Mark");
assertThat(updatedStudent.getStudentGrade()).isEqualTo(8);
}
#DisplayName("JUnit test for deleteStudent method")
#Test
public void givenStudentId_whenDeleteStudent_thenNothing() {
long studentId = 1L;
given(studentRepository.findById(studentId)).willReturn(Optional.of(student));
BDDMockito.willDoNothing().given(studentRepository).deleteById(studentId);
studentService.deleteStudent(studentId);
verify(studentRepository, times(1)).deleteById(studentId);
}
}
#Service
public class StudentServiceImpl implements StudentService {
#Autowired
private SubjectRepository subjectRepository;
private StudentRepository studentRepository;
public StudentServiceImpl(StudentRepository studentRepository) {
this.studentRepository = studentRepository;
}
#Override
public Student saveStudent(Student student) {
Collection<Remark> remarkList = new ArrayList<>();
List<Subject> subjects = subjectRepository.findAll();
for (Subject subject : subjects) {
Remark remark = new Remark();
remark.setSubject(subject);
remark.setStudent(student);
remark.setGrade(0);
remarkList.add(remark);
}
student.setRemarks(remarkList);
return studentRepository.save(student);
}
#Override
public List<Student> findAll() {
return studentRepository.findAll();
}
#Override
public Student findById(Long studentId) {
Optional<Student> student = studentRepository.findById(studentId);
if (!student.isPresent()) {
throw new ResourceNotFoundException("Student not found with id : " + studentId);
}
return studentRepository.findById(studentId).get();
}
#Override
public Student updateStudent(#PathVariable(value = "id") Long studentId, #RequestBody Student student) {
Optional<Student> tempStudent = studentRepository.findById(studentId);
if (!tempStudent.isPresent()) {
throw new ResourceNotFoundException("Student not found with id : " + studentId);
}
Student studentDetails = tempStudent.get();
studentDetails.setStudentName(student.getStudentName());
studentDetails.setStudentGrade(student.getStudentGrade());
studentDetails.getRemarks().addAll(student.getRemarks());
Student updatedStudent = studentRepository.save(studentDetails);
return updatedStudent;
}
#Override
public void deleteStudent(long studentId) {
Optional<Student> student = studentRepository.findById(studentId);
if (!student.isPresent()) {
throw new ResourceNotFoundException("Student not found with id : " + studentId +" or already deleted");
}
studentRepository.deleteById(studentId);
}
}

AspectJ not executing on Junit methods

Using AOP, I am trying to log test method execution time, but nothing happens when I run a test method.
I've tried to change regex in my pointcut but doesen't seem to be working.
My aspect class:
#Aspect
#Component
public class LoggableAspect {
#Pointcut("execution(public * com.mozzartbet.*.*.*Test.*(..))")
public void publicTestMethod() {}
#Around("publicTestMethod() && #annotation(loggable)")
public Object logTestExecutionTime(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {
long t1 = System.currentTimeMillis();
Logger logger = LoggerFactory.getLogger(joinPoint.getSignature().getDeclaringTypeName());
StringBuilder prefix = new StringBuilder(joinPoint.getSignature().getName()).append("()");
Object result = null;
try {
if (loggable.detail()) {
prefix.append(": ").append(Joiner.on(",").join(joinPoint.getArgs()));
}
result = joinPoint.proceed();
return result;
} finally {
long t2 = System.currentTimeMillis();
if (loggable.detail()) {
prefix.append(" -> ").append(result);
}
logger.info("{} took {} ms", prefix, t2 - t1);
}
}
}
My test class:
package com.mozzartbet.gameservice.services.impl;
public class PlayerServiceImplTest extends BaseServiceTest {
#Autowired
private PlayerService playerService;
#Test
#Loggable(detail = true)
public void testInsert() {
assertThat(playerService.insert(Player.builder().id("foo").build()), is(1));
}
}
Annotation:
#Retention(RUNTIME)
#Target(METHOD)
public #interface Loggable {
boolean detail() default false;
}
PlayerService insert method
#Override
public int insert(Player player) {
try {
return playerDao.insert(player);
} catch (DuplicateKeyException e) {
throw new PlayerException(PlayerExceptionCode.DUPLICATED_PLAYER_ID, "ID: %s is duplicated!", player.getId());
}
}
Dao insert method:
#Override
public int insert(Player player) {
return playerMapper.insert(player);
}
I am inserting with mybatis.
Your #annotation definition is incorrect.
You should specify the qualified package name of annotation.
#Around("publicTestMethod() && #annotation(your_package.Loggable)")

Spring Boot class cast exception in PostConstruct method

I am running a Spring Boot application with a PostConstruct method to populate a POJO before application initialization. This is to ensure that the database isn't hit by multiple requests to get the POJO content after it starts running.
I'm able to pull the data from Oracle database through Hibernate query and store it in my POJO. The problem arises when I try to access the stored data. The dataset contains a list of objects that contain strings and numbers. Just trying to print the description of the object at the top of the list raises a class cast exception. How should I mitigate this issue?
#Autowired
private TaskDescrBean taskBean;
#PostConstruct
public void loadDescriptions() {
TaskDataLoader taskData = new TaskDataLoader(taskBean.acquireDataSourceParams());
List<TaskDescription> taskList = tdf.getTaskDescription();
taskBean.setTaskDescriptionList(taskList);
System.out.println("Task description size: " + taskBean.getTaskDescriptionList().get(0).getTaskDescription());
}
My POJO class:
#Component
public class TaskDescrBean implements ApplicationContextAware {
#Resource
private Environment environment;
protected List<TaskDescription> taskDescriptionList;
public Properties acquireDataSourceParams() {
Properties dataSource = new Properties();
dataSource.setProperty("hibernate.connection.driver_class", environment.getProperty("spring.datasource.driver-class-name"));
dataSource.setProperty("hibernate.connection.url", environment.getProperty("spring.datasource.url"));
dataSource.setProperty("hibernate.connection.username", environment.getProperty("spring.datasource.username"));
dataSource.setProperty("hibernate.connection.password", environment.getProperty("spring.datasource.password"));
return dataSource;
}
public List<TaskDescription> getTaskDescriptionList() {
return taskDescriptionList;
}
public void setTaskDescriptionList(List<TaskDescription> taskDescriptionList) {
this.taskDescriptionList = taskDescriptionList;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
My DAO class:
public class TaskDataLoader {
private Session session;
private SessionFactory sessionFactory;
public TaskDataLoader(Properties connectionProperties) {
Configuration config = new Configuration().setProperties(connectionProperties);
config.addAnnotatedClass(TaskDescription.class);
sessionFactory = config.buildSessionFactory();
}
#SuppressWarnings("unchecked")
public List<TaskDescription> getTaskDescription() {
List<TaskDescription> taskList = null;
session = sessionFactory.openSession();
try {
String description = "from TaskDescription des";
Query taskDescriptionQuery = session.createQuery(description);
taskList = taskDescriptionQuery.list();
System.out.println("Task description fetched. " + taskList.getClass());
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}
return taskList;
}
TaskDescription Entity:
#Entity
#Table(name="TASK_DESCRIPTION")
#JsonIgnoreProperties
public class TaskDescription implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="TASK_DESCRIPTION_ID")
private Long taskDescriptionId;
#Column(name="TASK_DESCRIPTION")
private String taskDescription;
public Long getTaskDescriptionId() {
return taskDescriptionId;
}
public void setTaskDescriptionId(Long taskDescriptionId) {
this.taskDescriptionId = taskDescriptionId;
}
public String getTaskDescription() {
return taskDescription;
}
public void setTaskDescription(String taskDescription) {
this.taskDescription = taskDescription;
}
}
StackTrace
Instead of sending the List in the return statement, I transformed it into a JSON object and sent its String representation which I mapped back to the Object after transforming it using mapper.readValue()

JPA Callback not being called

I am new to hibernate. I want to know if any crud operation happens so I decided to use jpa callback annotations. The problem is any of those #PrePersist #PostPersist #PreRemove #PostRemove not being called when I run the project and use UI components to perform delete & add operations. I use primefaces datatable so delete operation bounded to a ManagedBean -> MessageService ->MessageDAO. IF I only execute the main file to test it it works perfectly
MessageDAO:
#Component
public class MessageDAO {
#PersistenceContext
private EntityManager em;
#Transactional
public void register(Message message) {
em.persist(message);
}
#Transactional
public void delete(Integer id) {
Message m = em.find(Message.class, id);
em.remove(em.merge(m));
}
}
MessageListener
public class MessageListener {
#PrePersist
public void prePersist(Message o) {
System.out.println("Pre-Persistiting operation: " );
}
#PostPersist
public void postPersist(Message o) {
System.out.println("Post-Persist operation: " );
}
#PreRemove
public void preRemove(Message o) {
System.out.println("Pre-Removing operation: " );
}
#PostRemove
public void postRemove(Message o) {
System.out.println("Post-Remove operation: " );
}
#PreUpdate
public void preUpdate(Message o) {
System.out.println("Pre-Updating operation: ");
}
#PostUpdate
public void postUpdate(Message o) {
System.out.println("Post-Update operation: " );
}
}
Message
#EntityListeners(MessageListener.class)
#Entity
#Table(name = "messages")
public class Message implements Serializable {
private Integer messageId;
private String subject;
private String content;
public Message(){}
public Message(Integer messageId, String subject, String content) {
this.messageId = messageId;
this.subject = subject;
this.content = content;
}
#Id
#GeneratedValue
#Column(name = "MESSAGE_ID")
public Integer getMessageId() {
return messageId;
}
//getter setter
#PrePersist
public void prePersist() {
System.out.println("OLDUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU!!!!!!!!!!!!");
}
}
As per the JPA spec, JPA callbacks/listeners are not called when using JPQL BULK DELETE. They are only called when using the JPA API (em.remove). Similarly the cache and managed entity objects do not reflect such a JPQL BULK DELETE call.
change Your code by following example hope it will work
#Transactional
public void delete(Long id) {
Message m = em.find(Message.class, id);
em.remove(em.merge(m));
}
}

Mockito mocking get methods from the database services

I am trying to mock a getBy() method after adding an element by a mocked service add.
This is what I have:
FeedItem feedItem = feedServiceTested.createFeedItem("Text Test", "Category Test", "Author Test");
Mockito.verify(feedRepository).add(feedItem);
Mockito.verify(feedRepository).findAllByCategory("Category Test");
However I get the following error:
Wanted but not invoked:
feedRepository.findAllByCategory(
"Category Test"
);
-> at ie.cit.adf.services.FeedServiceImplTest.testSearchFeedItemsByCategory(FeedServiceImplTest.java:55)
However, there were other interactions with this mock:
-> at ie.cit.adf.services.FeedServiceImpl.createFeedItem(FeedServiceImpl.java:44)
at ie.cit.adf.services.FeedServiceImplTest.testSearchFeedItemsByCategory(FeedServiceImplTest.java:55)
Any idea how to mock this findAllByCategory()?
Here are the 2 classes:
Repository:
#Secured("ROLE_USER")
public class JdbcFeedRepository implements FeedRepository {
private JdbcTemplate jdbcTemplate;
private FeedItemsMapper feedItemsMapper = new FeedItemsMapper();
public JdbcFeedRepository(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
#Override
public FeedItem findById(String feedItemId) {
return jdbcTemplate.queryForObject(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS WHERE ID=?",
feedItemsMapper,
feedItemId
);
}
#Override
public List<FeedItem> findAll() {
return jdbcTemplate.query(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS",
feedItemsMapper
);
}
#Override
public List<FeedItem> findAllByCategory(String category) {
return jdbcTemplate.query(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS WHERE CATEGORY=?",
feedItemsMapper,
category
);
}
#Override
public List<FeedItem> findAllByAuthor(String author) {
return jdbcTemplate.query(
"SELECT ID, TEXT, CATEGORY, AUTHOR FROM FEEDITEMS WHERE AUTHOR=?",
feedItemsMapper,
author
);
}
#Override
public void add(FeedItem feedItem) {
jdbcTemplate.update(
"INSERT INTO FEEDITEMS VALUES(?,?,?,?)",
feedItem.getId(),
feedItem.getText(),
feedItem.getCategory(),
feedItem.getAuthor()
);
}
#Override
public void delete(String feedItemId) {
jdbcTemplate.update("DELETE FROM FEEDITEMS WHERE ID=?", feedItemId);
}
/**
* Returns the name of the currently logged in Author.
*
* #return String
*/
private String getCurrentUser() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
}
class FeedItemsMapper implements RowMapper<FeedItem> {
#Override
public FeedItem mapRow(ResultSet rs, int rowNum) throws SQLException {
FeedItem feedItem = new FeedItem();
feedItem.setId(rs.getString("ID"));
feedItem.setText(rs.getString("TEXT"));
feedItem.setCategory(rs.getString("CATEGORY"));
feedItem.setAuthor(rs.getString("AUTHOR"));
return feedItem;
}
}
Service:
#Transactional
public class FeedServiceImpl implements FeedService {
private FeedRepository repo;
public FeedServiceImpl(FeedRepository repo) {
this.repo = repo;
}
#Override
public FeedItem get(String feedItemId) {
return repo.findById(feedItemId);
}
#Override
public List<FeedItem> getAllFeedItems() {
return repo.findAll();
}
#Override
public List<FeedItem> getAllFeedItemsByCategory(String category) {
return repo.findAllByCategory(category);
}
#Override
public List<FeedItem> getAuthorFeedItems(String author) {
return repo.findAllByAuthor(author);
}
#Override
public FeedItem createFeedItem(String text, String category, String author) {
FeedItem feedItem = new FeedItem();
feedItem.setText(text);
feedItem.setCategory(category);
feedItem.setAuthor(author);
repo.add(feedItem);
return feedItem;
}
#Override
public void delete(String feedItemId) {
repo.delete(feedItemId);
}
}
It seems your code never calls:
feedRepository.findAllByCategory("Category Test");
But you added a verifier for it. Mockito verify ensures the method is called one time in your test. When this did not happen its complains with an exception.
Your test calls:
feedServiceTested.createFeedItem(...)
Which only calls the following methods on repo:
add(feedItem)
Which is your first verify. So at the moment it seems your code did not use findAllByCategory and so does the verify throws this exception.
Or is there a call in FeedItem to the repo? Then please provide the code for this class too.

Resources