Null Pointer when using #SpringBootTest - spring-boot

I am using spring boot 1.4,
when using the #SpringBootTest annotation for integration test, it gives a null pointer.
#RunWith(SpringRunner.class);
#SpringBootTest
public class MyControllerTest {
#Test
public void mytest {
when().
get("/hello").
then().
body("hello");
}
}
and for main class:
#SpringApplication
#EnableCaching
#EnableAsync
public class HelloApp extends AsyncConfigureSupport {
public static void main(String[] args) {
SpringApplication.run(HelloApp.class, args);
}
#Override
public Executor getAsyncExecutor() {
...
}
}
Then in my controller:
#RestController
public class HelloController {
#Autowired
private HelloService helloService;
#RequestMapping("/hello");
public String hello() {
return helloService.sayHello();
}
}
HelloService
#Service
public class HelloService {
public String sayHello() {
return "hello";
}
}
But it ways says NullPointException when for helloService when processing request.
What am I missing?

You need to mock HelloService in your test class as your controller is calling a service .Here in your case Your Test class is not aware that there is any service available or not

The following example test class might help you. In this guide from spring an example is shown how to integration test a rest controller in a spring fashion way.
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class HelloControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void hello() throws Exception {
mockMvc.perform(get("/hello")).andExpect(content().string("hello"));
}
}

Related

Why did #TestConfiguration not create a bean for my test?

My service
#Service
public class StripeServiceImpl implements StripeService {
#Override
public int getCustomerId() {
return 2;
}
}
My test
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}
The error: java.lang.NullPointerException. I had checked and the stripeService is actually null.
Since you are autowiring you need an applicationcontext so that Spring can manage the bean and then can get injected in your class. Therefore you are missing an annotation to create the applicationcontext for your testclass.
I have updated your code and it works now(with junit 5 on your classpath). In the case dat you are using junit 4 it should be #RunWith(SpringRunner.class) instead of #ExtendWith(SpringExtension.class):
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfiguration.class)
public class StripeServiceTests {
#Autowired
StripeService stripeService;
#TestConfiguration
static class TestConfig {
#Bean
public StripeService employeeService() {
return new StripeServiceImpl();
}
}
#Test
public void findCustomerByEmail_customerExists_returnCustomer() {
assertThat(stripeService.getCustomerId()).isEqualTo(2);
}
}

Spring injection: #MockBean #Repository is not injected

I'm trying to #MockBean a #Repository annotated class:
#Repository
public interface ApplicationDao extends MongoRepository<Application, String> {}
I'm injecting it into a #Service annotated class:
#Service
public class AuthorizationService {
private ApplicationDao appsDao;
private List<Application> allowedApplications;
#Autowired
public AuthorizationService(ApplicationDao appsDao) {
this.appsDao = appsDao; //<<MOCKED INJECTED BEAN>>
this.fillApplications();
}
private void fillApplications() {
this.appsDao.findAll() //<<MOCKED method>>
.forEach(entry -> {
this.allowedApplications.put(entry.getName(), entry);
});
}
public bool isAuthorized(Application application) {
return this.allowedApplications
.stream()
.anyMatch(app -> app.getId().equals(application.getId()));
}
}
My test mocking configuration looks like:
#RunWith(SpringRunner.class)
#SpringBootTest()
public class GroupReferencesTest {
private #Autowired AuthorizationService;
private #MockBean ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app)); //<<FAILS>>
}
}
Nevertheless, my mocked object is not injected. I mean, when my AuthorizationService calls its injected ApplicationDao is returns an empty list instead of my mocked list.
I've tried to use #MockBean(name="applicationDao") as well. The behavior is the same.
I've also tried to configure my mocked bean using this code:
#TestConfiguration
public class RestTemplateTestConfiguration {
#Bean("applicationDao")
#Primary
public static ApplicationDao mockApplicationDao() {
ApplicationDao mock = Mockito.mock(ApplicationDao.class);
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(mock.findAll())
.thenReturn(allowedApplications);
return mock;
}
}
However, it doesn't works right.
Application class is:
public class Application {
private String id;
//setters & getters
}
Any ideas?
First things first - the type of test. Answer: Unit test.
You are starting Spring context that manages a lifecycle of AuthorizationService and then you are trying to inject mock. What really happens is that Spring IoC container is injecting a real ApplicationDao (the one managed by Spring IoC container) into the AuthorizationService.
Solution:
Manage lifecyle of AuthorizationService by your test runner (like MockitoJUnitRunner and inject ApplicationDao mock into it):
#RunWith(MockitoJUnitRunner.class)
public class GroupReferencesTest {
private #InjectMocks AuthorizationService authorizationService;
private #Mock ApplicationDao applicationDao;
#Before
public void setUp() {
Application testApplication = new Application();
testApplication.setName("test-application");
List<Application> allowedApplications = new ArrayList<Application>();
allowedApplications.add(testApplication);
Mockito
.when(this.applicationDao.findAll())
.thenReturn(allowedApplications);
}
#Test
public void test() {
Application app = new Application();
app.getId("test-application");
assertTrue(this.authorizationService.isAuthorized(app));
}
}
Working example
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {AuthorizationService.class})
public class GroupReferencesTest {
#Autowired
private AuthorizationService;
#MockBean
private ApplicationDao applicationDao;
#Test
public void test() {
//given
Mockito.when(applicationDao.findAll()).thenReturn(emptyList());
//when & then
assertTrue(authorizationService.isAuthorized(app));
}
}

Why #PostConstruct not invoked in spring container?

I tried to add some entities in the db shema
config:
#Configuration
#ComponentScan(ApplicationConfig.basePackage)
public class ApplicationConfig {
public final static String basePackage = "test"
}
spring container invocation:
public class StartApp {
public static void main(String... args) throws Exception{
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
TestEntityRepository repository = (TestEntityRepository) context.getBean("testEntityRepository");
repository.save(new TestEntity("test"));
}
}
target class with annotation:
public class PersistenceService {
#Autowired
TestEntityRepository testEntityRepository;
#PostConstruct
public void initialize(){
//repository.deleteAll();
testEntityRepository.save(new TestEntity("test1"));
testEntityRepository.save(new TestEntity("test2"));
testEntityRepository.save(new TestEntity("test3"));
}
}
as the result in table only one record - "test". At the Tomcat all works fine.
https://github.com/GlebSa/TestSpringJPA
It seems your PersistenceServiceis not recognized as a Service. Can you add the #Service to PersistenceService?
#Service
public class PersistenceService {
...
}
Hope this help.

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.

Spring Component with JUnitTests

I am using a Spring #Component which implements
ApplicationListener<ContextRefreshedEvent>. This component runs on tomcat startup, but when I run the unit tests, it runs the Component again. Why is that happening?
Here is the component -
BackGroundServices implements Thread.
#Component
public class RunBackgroundServices implements ApplicationListener<ContextRefreshedEvent> {
private final BackgroundServices backgroundServices;
private ExecutorService executor;
#Autowired
public RunBackgroundServices(BackgroundServices backgroundServices) {
this.backgroundServices= backgroundServices;
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
executor = Executors.newSingleThreadExecutor();
executor.submit(backgroundServices);
}
public void onApplicationEvent(ContextStoppedEvent event) {
executor.shutdown();
}
}
you can annotate the test like that
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { TestConfiguration.class}, loader = AnnotationConfigContextLoader.class)
public class MyTest{}
and then create your own configuration of jUnit tests when you can initialize only these beans that you want
#Configuration
public class TestConfiguration {
#Bean
poublic Xxx xxBean(){
}
}

Resources