#Before not setting up data during integration test - spring-boot

I am creating an integraiton test for a JpaRepository and the testcase fails with "Record not found with random value rand", as null is returned in the find results.
My test case:
#SpringBootTest
class JpatestsApplicationTests {
#Autowired
private JpaRepo jpaRepo;
#Before
void setup() {
FirstTable firstTable1 = new FirstTable();
firstTable1.setUid("x");
firstTable1.setRandom("rand");
jpaRepo.save(firstTable1);
}
#Test
void testFindByRandom() {
FirstTable f = jpaRepo.findByRandom("rand");//find by random value 'rand'
Assert.notNull(f, "Record not found with random value rand ");
}
The entity associated:
#Entity
#Table(name = "table1")
public class FirstTable {
#Id
#GeneratedValue
private String uid;
#Column
private String random;
And my Repository:
#Repository
public interface JpaRepo extends JpaRepository<FirstTable, Long> {
FirstTable findByRandom(String rand);
}
I am using h2 database.
Why is the result coming as null for findByRandom? Also please note that if I move the record saving part jpaRepo.save(firstTable1) to be within the test case (before the findByRandom("rand") is called, it gets passed.
Why wouldn't it work if I save the record in setup() method annotated with #Before ?

You have to add #Transactional on the top of your class.
#Transactional will cause your tests to execute within a test-managed transaction that will be rolled back after the test completes; code executed within the #Before method will be executed inside the test-managed transaction.

The latest version of spring-boot-test makes use of junit 5 and #Before is deprecated. It started working after changing to #BeforeAll with annotation of #TestInstance(TestInstance.Lifecycle.PER_CLASS) at the class level
My updated test class:
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class JpatestsApplicationTests {
#Autowired
private JpaRepo jpaRepo;
#BeforeAll
void setup() {
FirstTable firstTable1 = new FirstTable();
firstTable1.setUid("x");
firstTable1.setRandom("rand");
jpaRepo.save(firstTable1);
}
#Test
void testFindByRandom() {
FirstTable f = jpaRepo.findByRandom("rand");//find by random value 'rand'
Assert.notNull(f, "Record not found with random value rand ");
}
Chose BeforeAll over BeforeEach as I need to run it only once during execution of this class.
Reference: https://junit.org/junit5/docs/current/user-guide/

Related

How to mock ModelMapper for list in SpringBootTest using Junit and Mockito?

I have one API in which I am returning a list of DTO by mapping it with main entity object using model mapper
employeeList = employeeRepository.findAll();
employeeListPojos = employeeList.stream().map((emp) -> modelMapper.map(emp, EmployeeInfoPojo.class))
.collect(Collectors.toList());
I am trying to mock the model mapper in my test class but the same output is overriding in the test case
#ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {
#Mock
private EmployeeRepository employeeRepository;
#Mock
private ModelMapper modelMapper;
#InjectMocks
private EmployeesApiServiceImpl employeesApiService;
EmployeeEntity employee;
#BeforeEach
public void setup()
{
employee = EmployeeEntity.builder()
.id("1L")
.employeeName("Test employee")
.description("Dummy employee")
.build();
}
#DisplayName("Test Case For Getting The employee Object")
#Test
public void givenemployeeObject_whenGetemployeeHeader_thenReturnemployeeObject()
{
//given - precondition or setup
EmployeeEntity employee2 = employeeEntity.builder()
.id("2L")
.employeeName("Test employee 1")
.description("Dummy employee")
.build();
List<EmployeeEntity> employees = new ArrayList<EmployeeEntity>();
employees.add(employee);
employees.add(employee2);
BDDMockito.given(employeeRepository.findAll()).willReturn(employees);
employeeInfoPojo convertedPojo1 = employeeInfoPojo.builder()
.id("1L")
.employeeName("Test employee 2")
.description("Dummy employee")
.build();
EmployeeInfoPojo convertedPojo2 = employeeInfoPojo.builder()
.id("2L")
.employeeName("Test employee")
.description("Dummy employee")
.build();
List<EmployeeInfoPojo> employeesResult = new ArrayList<EmployeeInfoPojo>();
employeesResult.add(convertedPojo1);
employeesResult.add(convertedPojo2);
for(EmployeeInfoPojo co : employeesResult){
BDDMockito.when(modelMapper.map(any(),any()))
.thenReturn(co);
}
//when - action or behaviour need to be tested
List<EmployeeInfoPojo> result = employeesApiService.getemployeeList(null);
System.out.println(result);
//then - verify the output
Assertions.assertThat(result).isNotNull();
Assertions.assertThat(result.size()).isEqualTo(2);
}
}
Test case is passing but output of result is not correct the convertedPojo2 is overridden in both the entries of list.
Any suggestion how to mock ModelMapper that is used with list in Junit and Mockito.
Issue mostly in these lines of EmployeeServiceTest
for(EmployeeInfoPojo co : employeesResult){
BDDMockito.when(modelMapper.map(any(),any()))
.thenReturn(co);
}
The mock for modelMapper.map(...) will always return convertedPojo2 since you don't have any specific matcher in the for-loop. Each iteration of the for-loop will override the last mock method and hence the last mock will be used.
Instead of setting up the mock in a for-loop, add the specific mock mapping, e.g something like this:
when(modelMapper.map(eq(employee), eq(EmployeeInfoPojo.class)))
.thenReturn(convertedPojo1);
when(modelMapper.map(eq(employee2), eq(EmployeeInfoPojo.class)))
.thenReturn(convertedPojo2);
This will set up a mock for the mapper when employee is used as parameter, convertedPojo1 will be returned for employee2, convertedPojo2 will be returned

How to make Set using spring-data-aerospike

Environment:
spring-boot v2.0.4 RELEASE
spring-data-aerospike v2.0.1.RELEASE
java - 8
Here are my application code and properties.
// application.properties
aerospike.hosts=xxx:3000
aerospike.namespace=test
// aerospike configuration class
#Configuration
#RequiredArgsConstructor
#EnableConfigurationProperties(AerospikeConfiguration.AerospikeConfigurationProperties.class)
#EnableAerospikeRepositories(basePackageClassses = TestAeroRepository.class)
public class AerospikeConfiguration extends AbstractAerospikeDataConfiguration {
private final AerospikeConfigurationProperties aerospikeConfigurationProperties;
#Override
protected Collection<Host> getHosts() {
return Host.parseServiceHosts(aerospikeConfigurationProperties.getHosts());
}
#Override
protected String nameSpace() {
return aerospikeConfigurationProperties.getNamespace();
}
#Data
#Validate
#ConfigurationProperties("aerospike")
public static class AerospikeConfigurationProperties {
#NotEmpty
String hsots;
#NotEmpty
String namespace;
}
}
# Entity class
#Value
#Document
#Builder(toBuilder = true)
#AllArgsConstructor
public class testEntity() {
#Id
int id;
#Field
String name;
#Field
String timestamp;
}
#Repository
public interface TestAeroRepository extends AerospikeRepository<TestEntity, Integer> {
}
public interface TestAeroService {
void save();
}
#Service
#RequiredArgsConstructor
public class TestAeroServiceImpl implements TestAeroService {
private final TestAeroRepository testAeroRepository;
#Override
public void save(TestEntity entity) {
testAeroRepository.save(entity);
}
}
I checked Aerospike client connection has no problem.
But error is occurred when save() method is executed.
org.springframework.cglib.core.ReflectUtils.defineClass(Ljava/lang/String;[BLjava/lang/ClassLoader;Ljava/security/ProtectionDomain;Ljava/lang/Class;)Ljava/lang/Class;
Have to make sets before execute the application? I didn't make sets.
Any problem with my code?
You’re using an old version of spring-data-aerospike (2.0.1.RELEASE was released on April 2019) is there any chance you can upgrade to the latest version? 2.4.2.RELEASE
You can see how to setup a simple spring data aerospike application here: https://medium.com/aerospike-developer-blog/simple-web-application-using-java-spring-boot-aerospike-database-and-docker-ad13795e0089
Please share the entire project’s code and the entire exception.
I would look into:
The configuration class (The Aerospike Beans creation).
The content of the testEntity class - are you using #Id annotation on the primary key field?
Extending the repository class with specifying the testEntity object (… extends AerospikeRepository<testEntity, Object> {) you can see an example in the link I added.
The set is automatically created and takes the name of your object class, which is testEntity in your case. For example, based on your code, if you do not specify a collection in the #Document annotation a set named "testEntity" will automatically be created. I added the #Document(collection = "testEntitys") annotation and all I did was create two set. Once you insert your first record, run the "SHOW SETS" aql command and it will be there. So that's one way to do it.

How to make DataJpaTest flush save automatically?

I have an Employee entity with the following column:
#Entity
class Employee {
#Column(name = "first_name", length = 14)
private String firstName;
and I have a Spring JPA Repository for it:
#Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
In test/resources/application.properties I have the following so that I use an in-memory h2 database with tables auto-generated:
spring.jpa.hibernate.ddl-auto=create
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
I was expecting this test to fail, since the firstName is longer than what is allowed:
#DataJpaTest
public class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository employeeRepository;
#Test
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setFirstName("koraykoraykoray"); // 15 characters!
employeeRepository.save(employee);
}
}
And I was surprised to see this test was not failing, however the following does fail:
#DataJpaTest
public class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository employeeRepository;
#Test
public void testMustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setFirstName("koraykoraykoray"); // 15 characters!
employeeRepository.save(employee);
employeeRepository.findAll();
}
}
with the stacktrace:
Caused by: org.h2.jdbc.JdbcSQLDataException: Value too long for column "FIRST_NAME VARCHAR(14)": "'koraykoraykoray' (15)"; SQL statement:
The only difference is the second test has the additional employeeRepository.findAll(); statement, which forces Hibernate to flush as far as I understand.
This does not feel right to me, I would much rather want the test to fail immediately for save.
I can also have
#Autowired
private TestEntityManager testEntityManager;
and call
testEntityManager.flush();
but again, this does not feel correct either.. How do I make this test fail without any workaround or additional statements?
The easiest option in your case is configure #Transactional annotation, forcing to send database all changes in your tests (it can be used only in specific ones):
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.jupiter.api.Assertions.assertThrows;
#Transactional(propagation = Propagation.NOT_SUPPORTED)
#DataJpaTest
public class EmployeeRepositoryTest {
#Autowired
private EmployeeRepository employeeRepository;
#Test
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("koraykoraykoray"); // 15 characters!
assertThrows(DataIntegrityViolationException.class, () -> {
employeeRepository.save(employee);
});
}
#Test
public void mustSaveFirstNameShorterThan14() {
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("koraykor"); // 8 characters!
employeeRepository.save(employee);
}
}
PD: I have added a simple Integer property as PK of Employee entity due to your repository definition.
You can see the results in the following picture:
You could use JpaRepository<T,ID> instead of CrudRepository<T,ID>. Something like:
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Integer>
Then you can use its saveAndFlush() method anywhere you need to send data immediately:
#Test
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setFirstName("koraykoraykoray"); // 15 characters!
employeeRepository.saveAndFlush(employee);
}
And in code where you would like to have optimization you still can use save() method.
Thanks doctore for your answer, I had the similar problem as OP and your solution has helped. I decided to dig a little and figure out why it works, should someone else have this problem.
With #DataJpaTest annotated test class, your class implicitly becomes #Transactional with default propagation type Propagation.REQUIRED. That means every test method is also #Transactional with same default configuration. Now, all CRUD methods in CrudRepository are also #Transactional, but it has nothing to do with #DataJpaTest - they are transactional due to implementation. Whoa, that's a lot of transactions!
As soon as you annotate your whole class (or just a test method) with #Transactional(propagation = Propagation.NOT_SUPPORTED), your test method(s) are no longer #Transactional. However, inner methods of your test method(s), that is, CRUD operations from CrudRepository, remain transactional, meaning that they will have their own transaction scopes. Because of that, they will be committed to database immediately after execution, because by default (in Spring Boot, which users HikariCP connection pool), auto commits are turned on. Auto commits happen after every SQL query. And thus tests pass as you'd expect.
I like to visualize things, so here is the visualization of the whole process:
I hope this was helpful. URLs from the diagram:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
https://docs.oracle.com/javase/tutorial/jdbc/basics/transactions.html#disable_auto_commit
https://github.com/brettwooldridge/HikariCP/blob/dev/src/main/java/com/zaxxer/hikari/HikariConfig.java#L126
https://dzone.com/articles/spring-boot-transactions-tutorial-understanding-tr (not from diagram, but explains transaction very well!)
The #Commit can do the job ( it was added since 4.2)
#Test
#Commit
public void mustNotSaveFirstNameLongerThan14() {
Employee employee = new Employee();
employee.setId(1);
employee.setFirstName("koraykoraykoray"); // 15 characters!
assertThrows(DataIntegrityViolationException.class, () -> {
employeeRepository.save(employee);
});
}

OptimisticLockException not thrown when version has changed

I've created a simple EJB application that uses JPA for persistence and have a problem whereby optimistic locking is not functioning as I would have expected.
The application contains a class named Site which defines the model for a table named SITE in the database. The SITE table contains a column named ROW_VERSION which is referenced in the Site class using the #version annotation.
Whenever the record is updated, the ROW_VERSION is incremented by 1. So far, so good.
The problem arises when the row has changed in the time between the application reading the row using the EntityManager find method and the row being updated by the EntityManager merge method. As the ROW_VERSION for the row has been incremented by 1 and therefore is not the same as when the EntityManager find method was called, I would expect an OptimisticLockException to be thrown, but instead the changes are written to the table and in turn overwriting the changes made by the other process.
The application is running on WebSphere 8.5 and is using OpenJPA provided by the container.
Have I mis-understood how optimistic locking is supposed to work or is there something else that I need to do to make the OptimisticLockException occur?
The Site class is as follows:
#Entity
#Table(name="SITE")
public class Site {
#Id
#Column(name="SITE_ID")
private int id;
#Column(name="SITE_NAME")
private String siteName;
#Column(name="SITE_ADDRESS")
private String address;
#Column(name="ROW_VERSION")
#Version
private long rowVersion;
//getters and setters
}
The application makes uses of the Generic DAO wrapper class to invoke the EntityManager methods. The contents of the class are as follows:
public abstract class GenericDAO<T> {
private final static String UNIT_NAME = "Test4EJB";
#PersistenceContext(unitName = UNIT_NAME)
private EntityManager em;
private Class<T> entityClass;
public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}
public T update(T entity) {
return em.merge(entity);
}
public T find(int entityID) {
return em.find(entityClass, entityID);
}
//other methods
}
Update - I've done some more investigation and have found this http://pic.dhe.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=%2Fcom.ibm.websphere.nd.multiplatform.doc%2Finfo%2Fae%2Fae%2Fcejb_genversionID.html but even when I've added the #VersionColumn and #VersionStrategy annotations I still cannot get the OptimisticLockException to be thrown.

OpenEntityManagerInViewFilter Not Working In Unit Test

I'm writing a unit test for a controller, but when my test reaches the line where it called this method
private Predicate predicate( final Integer pid )
{
return
new Predicate()
{
public boolean evaluate( Object o )
{
ProviderAuxiliaryAccount proAux = ( ProviderAuxiliaryAccount) o;
return proAux.getProviderAccount().getId() == pid;
}
};
}
It throws a NullPointerException on this line:
return proAux.getProviderAccount().getId() == pid;
When I checked the ProviderAuxiliaryAccount object, It can not seem to retrieve its ProviderAccount property. Therefore, calling getProviderAccount().getId() will surely fire a null pointer exception. But this only happens during the unit test. I suspect that OpenEntityManagerInViewFilter is not working on the unit test.
Here are some excerpts from my java classes:
Controller Test class
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration( loader = CustomContextLoader.class, locations = {"/applicationContext-web-test.xml","/applicationContext-web-mail-test.xml"})
public class ControllerTest extends AbstractTransactionalJUnit4SpringContextTests
ProviderAuxiliaryAccount model
public class ProviderAuxiliaryAccount
implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer id;
private Integer providerId;
#XmlTransient
private ProviderAccount providerAccount;
3.Here's the part in my actual controller which called the method 'predicate'.
List<AuxiliaryAccount> accounts = auxiliaryService.getAuxiliaryAccounts( account.getPerson() );
ProviderAccount provider = auxiliaryService.getProviderAccount( UserAccountUtil.getUserName() );
AuxiliaryAccount aux =
( AuxiliaryAccount ) CollectionUtils.find( accounts, PredicateUtils.notNullPredicate() );
Integer pid = provider.getId();
if ( CollectionUtils.find( aux.getProviderAuxiliaryAccounts(), predicate( pid ) ) != null )
Notice that the ProviderAuxiliaryAccount has a transient ProviderAccount property. Also,
I added a #Transactional anotation on my controller test class as stated here.
OpenEntityManagerInView equivalent for Junit and Quartz Jobs .
But this doesn't seem to work for me.
Does anyone know how to fix this?

Resources