Spring batch + repository Testing - spring

This is my reader that work in job and step i'u using a repository to get users(public interface UserRepository extends JpaRepository<User,Long>):
#Slf4j
public class Reader implements ItemReader<User> {
#Autowired
UserRepository userRepository;
private Iterator<User>userIterator;
#BeforeStep
public void before(StepExecution execution){
userIterator=userRepository.findAll().iterator();
}
#Override
public User read() {
if (userIterator != null && userIterator.hasNext()) {
User user=userIterator.next();
log.info("User-->"+user.toString());
return user;
} else {
return null;
}
}
}
This is my test class:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {SpringBatchApplication.class, BatchTestConfiguration.class})
public class SpringBatchApplicationTest {
#Autowired
private JobLauncherTestUtils testUtils;
#Autowired
private BatchConfig config;
#Test
public void testEntireJob() throws Exception {
final JobExecution result = testUtils.getJobLauncher().run(config.processJob(), testUtils.getUniqueJobParameters());
Assert.assertNotNull(result);
Assert.assertEquals(BatchStatus.COMPLETED, result.getStatus());
}
#Test
public void testSpecificStep() {
Assert.assertEquals(BatchStatus.COMPLETED, testUtils.launchStep("orderStep1").getStatus());
}
}
When i`m running my test i got a :
Caused by: java.lang.IllegalStateException: Cannot determine embedded database for tests. If you want an embedded database please put a supported one on the classpath.
What do i need to add to make determine of my database. Do i need to place application properties somewhere or something else?
There is how my test situate in project enter image description here

Related

Spring boot repository.save() does not work in test class

I have this test class:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = { CrimeServiceDBImpl.class, CrimeController.class, Crime.class })
#ComponentScan("com.springmiddleware")
#EntityScan(basePackages = {"com.springmiddleware.entities"})
#DataJpaTest
#AutoConfigureTestDatabase(replace = Replace.NONE)
#EnableJpaRepositories("com.springmiddleware")
public class TestCrimeServiceDB {
#Autowired
private CrimeServiceDBImpl service = new CrimeServiceDBImpl();
#Test
public void getAll() {
try {
List<Crime> list = this.service.getAllCrimes();
assertTrue(list.size()!=0);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The method getAllCrimes() from the service class does just this:
#Service
public class CrimeServiceDBImpl implements CrimeService{
#Autowired
private CrimeRepository repository;
private List<Crime> list = new ArrayList<Crime>();
public CrimeServiceDBImpl() {
list = UtilityMethods.readFromCSV();
};
#Override
public List<Crime> getAllCrimes() throws IOException {
repository.saveAll(list);
return this.repository.findAll();
}
If I call this method when running the application, it correctly add all my objects to the database, but when it's called from the test it doesn't add anything, but no exception is thrown.
Which database are you using? Do you mean the data is not persisted in the database after the test has finished? That's because a test always perform a rollback/cleanup when it has finished its work.

No primary or default constructor found for Pageable in Pact Contract Provider test

I set up following pact contract provider test
#RunWith(SpringRestPactRunner.class)
#Provider("structures")
#PactFolder("pacts")
#VerificationReports({"console", "markdown"})
#SpringBootTest
public class ContractTest {
#MockBean
private MyServiceImpl myServiceImpl;
#Autowired
private MyController myController;
#Configuration
public static class TestConfiguration {
#Bean
public MyController myController() {
return new MyController();
}
}
#TestTarget
public final MockMvcTarget target = new MockMvcTarget();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
target.setControllers(myController);
}
#State("My state")
public void setupDocumentWithStructures() {
Mockito.when(myService.getStructuresByDocumentId(
ArgumentMatchers.eq("1"),
ArgumentMatchers.any()
)).thenReturn(new PageImpl<>(Arrays.asList(
Structure.of("first"),
Structure.of("second")
)));
}
}
Running the test results in:
java.lang.AssertionError:
0 - Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.data.domain.Pageable
java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.data.domain.Pageable
The method getStructuresByDocumentId expects a Pageable object as its second argument. Changing the annotation #SpringBootTest to
#WebMvcTest(MyController.class)
#EnableSpringDataWebSupport
Doesn't solve the problem. Any ideas, how to solve this issue?
you used "myService" in your setupDocumentWithStructures whereas your #MockBean is myServiceImpl.......I think you meant to use myServiceImpl in setupDocumentWithStructures
That's how it can work
#Before
public void setupOrInit() {
this.mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setControllerAdvice(new ErrorRequestInterceptor(tracer))
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
}
I was having the same problem and fixed setting a new mockMvc like this
#Before
public void before() {
MockitoAnnotations.initMocks(this);
target.setMockMvc(MockMvcBuilders.standaloneSetup(myController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build());
}
I am not using #SpringBootTest as you are, but I think in this case it does not matter. Below is my entire (redacted) code.
#RunWith(SpringRestPactRunner.class)
#Provider("my-provider")
#PactBroker(url = "https://pact-broker.my-compnay.com")
public class MyControllerProviderContractTest {
#TestTarget
public final MockMvcTarget target = new MockMvcTarget();
#Mock
private MyService myService;
#InjectMocks
private MyController myController = new MyController();
#Before
public void before() {
MockitoAnnotations.initMocks(this);
target.setMockMvc(MockMvcBuilders.standaloneSetup(myController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build());
}
#State("my state")
public void stateForMyMethod() {
//my mocks
}
}
I hope this helps, I spend a few hours trying to solve this.
Cheers

Unit Testing using JUnit for Spring Batch without XML configuration

I am new to Spring Batch and I started developping a simple batch application. Now I am thinking of some unit testing unsing JUnit that could be healthy for my app and code ;)
The problem is that I couldn't find any ressource (examples, tutos ...) on the internet that shows how to perform unit testing with Spring Batch when using no XML.
Here is my code to be more clear :
Config class:
package my.company.project.name.batch.config
#Configuration
#EnableBatchProcessing
#ComponentScan({
"my.company.project.name.batch.reader",
"my.company.project.name.batch.tasklet",
"my.company.project.name.batch.processor",
"my.company.project.name.batch.writer"
})
#Import({CommonConfig.class})
public class MyItemBatchConfig {
#Autowired
private StepBuilderFactory steps;
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private MyItemTasklet myItemTasklet;
#Bean
public Job myItemJob(#Qualifier("myItem") Step loadProducts){
return jobBuilderFactory.get("myItemJob").start(myMethod).build();
}
#Bean(name= "myItem")
public Step myMethod(){
return steps.get("myItem").tasklet(myItemTasklet).build();
}
}
MyItemReader class :
package my.company.project.name.batch.reader
#Component
public class MyItemReader implements ItemReader<MyItem>{
#Value("${batch.load.produit.csv.file.path}")
private String csvFilePath;
private LinkedList<CsvRawLine> myItems;
#PostConstruct
public void init() {
myItems = new LinkedList<>(CsvUtil.getCsvReader(MyItem.class, csvFilePath));
}
#Override
public MyItem read() throws Exception{
return myItems.poll();
}
}
ItemProcessor class :
package my.company.project.name.batch.processor
#Component
public class MyItemProcessor implements ItemProcessor<MyItem, MyItemProcessorResult> {
public MyItemProcessorResult process(MyItemitem) throws Exception {
//processing business logic
}
}
ItemWriter class :
package my.company.project.name.batch.writer
#Component
public class MyItemWriter implements ItemWriter<MyItem> {
#Override
public void write(List<? extends MyItem> myItems) throws Exception {
//writer business logic
}
}
MyItemTasklet class that will call all the previous classes in order to achieve the task wanted by the batch:
package package my.company.project.name.batch.tasklet
#Component
public class MyItemBatchTasklet implements Tasklet{
#Autowired
public MyItemReader myItemReader;
#Autowired
public MyItemProcessor myItemProcessor;
#Autowired
public MyItemeWriter myItemWriter;
#Override
public RepeatStatus execute execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
//calling myItemReader, myItemProcessor and myItemWriter to do the business logic
return RepeatStatus.FINISHED
}
}
MyItemTasklet class that will launch the tasklet by its main method :
package package my.company.project.name.batch
public class MyItemTaskletLauncher{
public MyItemTaskletLauncher(){
//No implementation
}
public static void main (String[] args) throws IOException, JobExecutionException, NamingException {
Launcher.launchWithConfig("Launching MyItemTasklet ...", MyItemBatchConfig.class,false);
}
}
I made a simple batch application using Spring Batch and MyBatis and JUnit.
The test codes of application runs unit testing without XML.
Here is test class for Job.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = {xxx.class, yyy.class, zzz.class, xxxJobLauncherTestUtils.class})
public class JobTest {
#Autowired
#Qualifier(value = "xxxJobLauncherTestUtils")
private JobLauncherTestUtils xxxJobLauncherTestUtils;
#Test
public void testXxxJob() throws Exception {
JobExecution jobExecution = xxxJobLauncherTestUtils.launchJob();
assertThat(jobExecution.getStatus(), is(BatchStatus.COMPLETED));
}
}
#Component(value = "xxxJobLauncherTestUtils")
class XxxjobLauncherTestUtils extends JobLauncherTestUtils {
#Autowired
#Qualifier(value = "xxxJob")
#Override
public void setJob(Job job) {
super.setJob(job);
}
}
About details, please see the below link.
https://github.com/Maeno/spring-batch-example/tree/master/src/test
I hope that it will be helpful.

Static field injection in Spring Unit test

I am using JUnit4 in my application where I tried to test a UserService, the current test case is simple:
Create a user named 'admin' and save it to the database.
The other test case will rely on this user.
So I use the BeforeClass to insert the record, however I have to use the UserService to save the user, but spring does not support to inject static fields.
When I tried to create the UserService manually, I found that I have to fill the dependencies myself, I wonder if there is an alternative? Or there is something wrong with how I use JUnit?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:spring/application-config.xml"})
public class UserServiceTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
#Autowired
private UserService userService;
//#Autowired // sprint does not suport this
private static UserService us;
private static User u;
#BeforeClass
public static void before() {
us = new UserServiceImpl(); // this UserService instance can not be used, since I have to fill the dependencies manually
us.clear();
u = new User();
u.setUsername("admin");
u.setPassword("pass");
us.save(u);
}
#AfterClass
public static void after() {
userService.delete(u.getId());
}
#Test
public void testQuery() {
List<User> list = userService.find();
assertEquals(1, list.size());
}
#Test
public void testChangePassword() {
userService.changePassword(u.getId(), u.getPassword(), "newpass");
assertEquals("newpass", userService.findOne(u.getId()).getPassword());
exception.expect(ResourceNotFoundException.class);
userService.changePassword("1", "32", "ss");
exception.expect(ResourceNotFoundException.class);
userService.changePassword(u.getId(), "32", "ss");
}
}

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