Spring Test Transaction Rollback Problem - spring

i have a Problem understanding the #Transactional and #TransactionConfiguration(defaultRollback = true) Annotations.
I have a test Code which inserts a userAccount into the Database, then another account with the same name should be inserted, which should result in a DataIntegrityViolationException because the AccountName is marked as Unique. This works fine if #Transactional and #TransactionConfiguration(defaultRollback = true) is not sepcified at the TestClass level. But if Rollback is enabled i don't get the Exception because even in the same method the Data is not inserted into the databasse. If i set a breakpoint after inserting the first Account, the Database is still empty.
Here is my Code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/spring/applicationContext.xml"})
#Transactional
#TransactionConfiguration(defaultRollback = true)
public class DaoTests {
#Autowired
private Repository repo;
#Autowired
private AccountService userService;
#Before
public void orgInstAccount() {
Organization o = new Organization();
o.setName("Organisation 1");
repo.saveEntity(o);
Institution i1 = new Institution();
i1.setName("xyz");
i1.setOwningOrganization(o);
repo.saveEntity(i1);
}
#Test(expected = DataIntegrityViolationException.class)
public void saveUserFail() {
Account user = new Account();
user.setAccountname("chz");
user.setPassword(userService.calcMD5Hash("123"));
user.setOwningInstitution(repo.getInstitutionByName("xyz"));
repo.saveEntity(user);
Assert.assertNotNull(repo.getAccountByName("chz"));
Account userNew = new Account();
userNew.setAccountname("chz");
userNew.setPassword(userService.calcMD5Hash("123"));
userNew.setOwningInstitution(repo.getInstitutionByName("xyz"));
repo.saveEntity(userNew);
//Here the Exception should be thrown but everything works fine.
}
}
The Repository Implementation is:
#Repository
#Transactional
#SuppressWarnings("unchecked")
public class RepositoryHibernateImpl implements Repository {
#Autowired
private SessionFactory factory;
#Override
public void saveEntity(Entity hce) {
factory.getCurrentSession().save(hce);
}
}
Maybe the Problem is because the Repository and the TestClass are marked with #Transactional?
Thank you in Advance.

Call flush() which will try to call sql immediatly instead of deferring it till transaction boundary
factory.getCurrentSession().flush()

Related

Jpa Auditing test null in getCreatedBy, and getLastModifiedBy

Hi I am trying to write unit test for Auditing
#DataJpaTest
#EnableJpaAuditing
#RunWith(SpringRunner.class)
#AutoConfigureEmbeddedDatabase(type=POSTGRES)
public class MyTestAuditor {
#Autowired
private TestEntityManager entityManager;
#Test
public void auditTest() throws InterruptedException {
final MyEntity testEntity = MyEntity.builder()
....
.build();
SLOEntity entity = entityManager.persistAndFlush(testEntity);
assertNotNull(testEntity.getCreatedOn());
assertNotNull(testEntity.getLastModifiedOn());
assertNotNull(testEntity.getCreatedBy());
assertNotNull(testEntity.getLastModifiedBy());
}
}
I pass first two assertion, the timestamp ones, but fail the username part. Is there anything I am missing here, thanks:)

Testing service layer in Spring Boot using Mockito

I am trying to unit test my service layer using mockito having a connection to a Database through the Repository layer.
My test case:
#InjectMocks
private EmployeeService employeeService;
#Mock
private EmployeeRepository employeeRepository;
#Test
public void getActionFromEmployeeIdTest() throws ActionException {
//setup
when(employeeRepository.getActionsByEmployeeId(anyLong()).thenReturn(EmployeeEntity);
// exercise
List<Employee> result = employeeService.getActionsByEmployeeIdService(101);
//verify
assertEqual(EmployeeEntity, result);
}
Service Layer:
#Service
public class EmployeeService {
#Override
public List<EmployeeUser> getActionsByEmployeeIdService(long employeeId) {
Employee employee = employeeRepository.findByEmployeeIdId(employeeId);
List<EmployeeUser> actions = employeeUserRepository.getActionsByEmployeeId(employeeId);
return actions;
}
Repository layer:
#Repository
public interface EmployeeUserRepository extends JpaRepository<EmployeeUser,Long> {
#Transactional
#Query(value = "Select e from EmployeeUser e where e.employeeId = :employeeId" )
List<EmployeeUser> getActionsByEmployeeId(#Param("employeeId") long employeeId);
}
I am using #InjectMocks for employeeService and #Mock for employeeRepository.
result seems to be returning null. Is there anyway I can return a non-null value in my test?
You are using reference of employeeRepository to call getActionssByEmployeeId(anyLong()) method.
when(employeeRepository.getActionssByEmployeeId(anyLong()).thenReturn(EmployeeEntity);
But in service calss this methos is getting called by employeeUserRepository
List<EmployeeUser> actions = employeeUserRepository.getActionsByEmployeeIdId(employeeId);
Please check this.

#Rollback in TestNG Integration Test but entry in DB committed

#ContextConfiguration(classes = { ServiceConfig.class,PersistenceConfiguration.class, MailConfig.class })
#Transactional
public class CreateStatsIT extends AbstractTestNGSpringContextTests {
#Autowired
private UserRepository userRepository;
#Test
#Rollback
#Transactional
public void insertUserIT() {
User u = new User(1L, "Test");
u = userRepository.save(s);
List<User> us = userRepository.findAll();
System.out.println(us.size());
}
}
I would expect that the user would not be present in the database after the completion of the test but it is. The Spring Integration Tests documentation describes that the tests rollback automatically and also that #Rollback does not let the transaction be committed.
What am I doing wrong?

Using #SpyBean with #Qualifier Spring Boot Test

I have 2 DataSources in my app.
So, to get the required JdbcTemplate, i use #Qualifier. But, when i do like below, the test runs... but stays waiting indefinitely, if there is any use of JdbcTemplate in the "Method Under Test".
#Service
#Transactional
public class SampleDatabaseService {
#Autowired
#Qualifier("firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;
#Autowired
#Qualifier("secondDbJdbcTemplate")
private JdbcTemplate secondDbJdbcTemplate;
#Cacheable("status")
public Map<String, Device> readAllValidDeviceStatus() {
Map<String, Device> allDeviceStatuses = new HashMap<>();
//Stops at below line indefinitely if "SpyBean" is used
List<StatusDetail> statusDetails = firstDbJdbcTemplate
.query(SqlQueries.READ_DEVICE_STATUS, BeanPropertyRowMapper.newInstance(StatusDetail.class));
statusDetails
.stream()
.filter(deviceStatus -> deviceStatus.getName() != "Some Invalid Name")
.forEach(deviceStatus -> allDeviceStatuses
.put(deviceStatus.getName(), buildDevice(deviceStatus)));
return allDeviceStatuses;
}
/** More Stuff **/
}
and the Test :
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Transactional
#Rollback
#ActiveProfiles("test")
public class SampleDatabaseServiceTest {
#SpyBean
#Qualifier("firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;
#Autowired
private SampleDatabaseService serviceUnderTest;
#Before
public void populateTables() {
//Insert some Dummy Records in "InMemory HSQL DB" using firstDbJdbcTemplate
}
#Test
public void testReadAllValidDeviceStatus() {
// When
Map<String, Device> allDeviceStatuses = serviceUnderTest.readAllValidDeviceStatus();
// Then
assertThat(allDeviceStatuses).isNotNull().isNotEmpty();
// More checks
}
/* More Tests */
}
But, when i replace the #SpyBean with #Autowired in Test, it works fine.
Why is it so? Any help is greatly appreciated. :)
Use it in below format
#MockBean(name = "firstDbJdbcTemplate")
private JdbcTemplate firstDbJdbcTemplate;

Spring boot and Security Integration test with EntityManager

I want to test my spring application. It requires authentication, so I create an user object and persist it in #Before method. But i can not do authentication because, as i think, init() method is executed in another session.
IntegrationTest class:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
#Transactional
public class IntegrationTest {
#PersistenceContext
private EntityManager entityManager;
#Autowired
private PasswordEncoder passwordEncoder;
#LocalServerPort
int port;
private String URL;
#Before
public void init() {
User user = new User();
user.setUsername("testUser");
user.setPassword(passwordEncoder.encode("test"));
user.setEmail("test#test.com");
user.setEnabled(true);
entityManager.persist(user);
entityManager.flush();
entityManager.clear();
RestAssured.port = port;
URL = "http://localhost:" + String.valueOf(port) + "/users/user";
}
#Test
public void givenNotAuthenticatedUser_whenLoggingIn_thenCorrect() {
final RequestSpecification request = RestAssured.given().auth().basic("testUser", "test");
request.when().get(URL).then().assertThat().statusCode(200);
}
}
But if I use my userRepository and call
userRepository.save(user);
instead of
entityManager.persist(user);
entityManager.flush();
entityManager.clear();
everything works fine. I also have to remove #Transactional annotation.
Firstly I thought it was because, there was no commit - I saw that there is no changes in the user table. How to force EntityManager to commit data?
How to use EntityManager in test? And why UserRepository does work well?
As stated in the documentation:
By default, the framework will create and roll back a transaction for each test.
You can override it using #Commit on your test class and put TestTransaction.end() after entityManager.clear().
Now the test works ok but I still can not understand why and how UserRepository works without commiting the transaction.

Resources