Testing dao layer with #DataJpaTest - spring

I am writing unit testing using #DataJpaTest. Though it should do automatic rollback after every method, it is not doing that. Can you please help me with this.
This has 2 test cases written, ideally, test2 should return null, but it returns 1.
#RunWith(SpringRunner.class)
#DataJpaTest
public class EmployeeRepositoryTest {
#Autowired TestEntityManager em;
#Autowired EmployeeRepository rep;
// #Autowired EmployeeService service;
//Spring context loaded only once, reused by other methods
#Test
public void test1() {
// System.out.println(service); No such bean found
Employee e= new Employee();
e.setName("Payal");
em.persist(e);
em.flush();
Employee emp=rep.findByName("Payal");
assertNotNull(emp);
assertThat(emp.getId()).isGreaterThan(0);
}
#Test
public void test2() {
Employee emp=rep.findByName("Payal");
assertNull(emp);
}
}
Complete code can be found at:
https://github.com/payalbnsl/SpringUnitTestDemo/tree/master/src/test/java/com/example/demo/dao

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:)

Spring Boot Unit Testing MockMvc Null Body

I am having dificulties with using MockMvc.
Here I have simple Service and controller classes:
Service:
#Slf4j
#Service
public class EmployeeService {
//...
public Employee GetSample() {
//...
//filling Employee Entities
return new Employee(
"Harriet"
, "random"
, 25);
}
}
controller:
#RestController
#RequestMapping(value = "/info")
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
#Validated
public class EmployeeController {
private final EmployeeService employeeService;
#PostMapping("/GetEmployee")
public ResponseEntity<Employee> GetEmployee() {
Employee employee = employeeService.GetSample();
return new ResponseEntity<>(employee, HttpStatus.OK);
}
}
Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EmployeeTestCase {
private MockMvc mockMvc;
#InjectMocks
private EmployeeController EmployeeController;
#Mock
private EmployeeService employeeService;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.standaloneSetup(employeeController).build();
}
#Test
public void getEmployee() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/info/GetEmployee")).andDo(print());
}
}
when I try to use MockMvc I get null body. It seems employee is null. But I didn't understand why.
I thought that when test uses perform, it should initialise employee and later on it should't be null.
I tried to cut the code as much as possible. I hope it is not long.
Note : also tried to use Mockito.when(employeeController.GetEmployee()).thenCallRealMethod();
The #SpringBootTest annotation loads the complete Spring application
context. That means you do not mock your layers
(Services/Controllers).
If you wanted to test specific layers of your application, you could look into test slice annotations offered by Springboot: https://docs.spring.io/spring-boot/docs/current/reference/html/test-auto-configuration.html
In contrast, a test slice annotation only loads beans required to test a particular layer. And because of this, we can avoid unnecessary mocking and side effects.
An example of a Test Slice is #WebMvcTest
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = HelloController.class,
excludeFilters = {
#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
)
public class HelloControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void hello() throws Exception {
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
#Test
public void helloDto() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.amount", is(amount)));
}
}
However if you really wanted to load up the SpringBoot Application context, say for an Integration Test, then you have a few options:
#SpringBootTest
#AutoConfigureMockMvc
public class TestingWebApplicationTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello, World")));
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class AuctionControllerIntTest {
#Autowired
AuctionController controller;
#Autowired
ObjectMapper mapper;
MockMvc mockMvc;
#Before
public void setUp() throws Exception {
System.out.println("setup()...");
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void create_ValidAuction_ShouldAddNewAuction() throws Exception {
final Auction auction = new Auction(
"Standing Desk",
"Stand up desk to help you stretch your legs during the day.",
"Johnnie34",
350.00);
mockMvc.perform(post("/auctions")
.contentType(MediaType.APPLICATION_JSON)
.content(toJson(auction)))
.andExpect(status().isCreated());
}
}
Lets say you don't want to load up any layers at all, and you want to mock everything, such as for example a Unit Test:
#RunWith(MockitoJUnitRunner.class)
class DemoApplicationTest {
#Mock
private UserRepository userRepository;
private Demo noneAutoWiredDemoInstance;
#Test
public void testConstructorCreation() {
MockitoAnnotations.initMocks(this);
Mockito.when(userRepository.count()).thenReturn(0L);
noneAutoWiredDemoInstance = new Demo(userRepository);
Assertions.assertEquals("Count: 0", noneAutoWiredDemoInstance.toString());
}
}

Spring test transaction thread

I have moved a synchronous process to asynchronous, and now I have some troubles to maintain integration tests. It seems related to the fact that when you create a new thread inside a #Transactional method, then call a new #Transactional, Spring create a new transaction.
During integration tests the problem occurs with #Transactional tests. It seems that the thread transaction is rollbacked before the test finishes because of TransactionalTestExecutionListener in test configuration.
I'have tried many things like
- autowiring EntityManager and manually flushing after thread was finished
- using #Rollback instead of #Transactional in test methods
- managing transactions with TestTransaction
- using #Rollback and TestTransaction together
Here is the simplified source code :
public interface MyService{
public void doThing(someArgs...);
public void updateThings(someArgs...);
}
#Service
public class MyServiceImpl implements MyService{
#Autowired
private AsynchronousFutureHandlerService futureService;
#Autowired
#Qualifier("myExecutorService")
private ScheduledExecutorService myExecutorService;
#Transactional
#Override
public void doThing(someArgs...){
doThingAsync(someArgs...);
}
private void doThingAsync(someArgs...){
AsynchronousHandler runnable = applicationContext.getBean(
AsynchronousHandler.class, someArgs...);
//as we are executing some treatment in a new Thread, a new transaction is automatically created
Future<?> future = myExecutorService.submit(runnable);
//keep track of thread execution
futureService.addFutures(future);
}
#Override
#Transactional
public void updateThings(someArgs...){
//do udpate stuff
}
}
/**
* very basic solution to improve later to consult thread state
*/
#Service
public class AsynchronousFutureHandlerService {
//TODO : pass to ThreadSafe collection
private List<Future<?>> futures = new ArrayList<>();
public void addTheoreticalApplicationFuture(Future<?> future){
futures.add(future);
this.deleteJobsDone();
}
public boolean isThreadStillRunning(){
boolean stillRunning = false;
for(Future<?> f : futures){
if(!f.isDone()){
stillRunning = true;
break;
}
}
return stillRunning;
}
public void deleteJobsDone(){
this.futures.removeIf(f -> f.isDone());
}
}
#Component
#Scope("prototype")
public class AsynchronousHandler implements Runnable {
#Autowired
private MyService myService;
#Override
public void run() {
myService.updateThings(...); //updates data in DB
...
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = TestConfiguration.class)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DataSetTestExecutionListener.class,
TransactionalTestExecutionListener.class })
#DataSet(dbType = DBType.H2, locations = { "classpath:dataset.xml" })
public class MyServiceTest{
#Autowired
private MyService myService;
#Autowired
private AsynchronousFutureHandlerService futureService;
#Test
#Transactional
public void test_doThings(){
myService.doThings(someArgs...);
waitUpdateFinish();
Assert.assertEquals(...); //fails here because Thread transaction has been rollbacked
}
private void waitUpdateFinish() throws InterruptedException{
while(futureService.isThreadStillRunning()){
Thread.sleep(500);
}
}
}

#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?

Spring JUnit testing with #Autowired annotation

I´m having issues with my test cases after having introduced #Autowired in one of the classes under test.
My testcase now looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"/applicationContext.xml", "/spring-security.xml"})
public class StudentRepositoryTest extends AbstractDatabaseTestCase {
private StudentRepository studentRepository;
private CompanyRepository companyRepository;
private Student testStudent;
private Company testCompany;
#Before
public void setUp() {
studentRepository = new StudentRepository();
studentRepository.setJdbcTemplate(getJdbcTemplate());
testStudent = Utils.testStudentNoApplication();
}
#Test
....
}
StudentRepository now looks like this:
#Service
public class StudentRepository extends AbstractRepository<Student> {
...
private PasswordEncoder passwordEncoder;
private MailService mailService;
public StudentRepository() {
// TODO Auto-generated constructor stub
}
#Autowired
public StudentRepository(MailService mailService, PasswordEncoder passwordEncoder) {
this.mailService = mailService;
this.passwordEncoder = passwordEncoder;
}
Obviously this test case won´t work anymore.
But what changes do I need to make to the testcase for the #Autowired annotation to be picked up by the test case?
EDIT:
I´ve now updated my setUp() to this (I need the password encoder to avoid null password):
#Before
public void setUp() {
//studentRepository = new StudentRepository();
studentRepository = new StudentRepository(mock(MailService.class), ctx.getAutowireCapableBeanFactory().createBean(ShaPasswordEncoder.class));
studentRepository.setJdbcTemplate(getJdbcTemplate());
testStudent = Utils.testStudentNoApplication();
}
My testcase is now running OK, but my testsuite failes with a NullPointerException.
I´m guessing the ApplicationContext is not being Autowired when running the testsuite for some reason?
If you don't want to declare your StudentRepository in one of XML files referenced by #ContextConfiguration and autowire it into the test, you can try to use AutowireCapableBeanFactory as follows:
...
public class StudentRepositoryTest extends AbstractDatabaseTestCase {
...
#Autowired ApplicationContext ctx;
#Before
public void setUp() {
studentRepository = ctx.getAutowireCapableBeanFactory()
.createBean(StudentRepository.class);
...
}
...
}

Resources