Spring Starter Test - JUnit SpringBoot - spring

Hello im new in testing and I first time trying to test a JpaRepository which interact with postgres in reality but in test it interacte with H2 Db i ve installed H2 dependencie and the software aswell but i still have a problem when using the repository on my test btw the dependencie is mention in scope test just to clarify more, any whenever i run this test below i got this error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field initService in com.project.socializer.SocializerApplication required a bean of type 'com.project.socializer.runner.InitService' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.project.socializer.runner.InitService' in your configuration.
`***************************
APPLICATION FAILED TO START
***************************
Description:
Field initService in com.project.socializer.SocializerApplication required a bean of type 'com.project.socializer.runner.InitService' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.project.socializer.runner.InitService' in your configuration.`
here is my code :
package com.project.socializer.user.repository;
import com.project.socializer.SocializerApplication;
import com.project.socializer.user.entity.Roles;
import com.project.socializer.user.entity.UserEntity;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
#DataJpaTest
class UserRepositoryTest {
#Autowired
UserRepository userRepository;
#BeforeEach
void setUp() {
userRepository.save(new UserEntity("Jhon","Doe","jhon.doe#gmail.com","test1234","1999-12-19",new Roles("USER")));
}
#AfterEach
void afterEach() {
userRepository.deleteAll();
}
#Test
void findByEmail() {
Optional<UserEntity> userTest = userRepository.findByEmail("jhon.doe#gmail.com");
assertTrue(userTest.isPresent(),"User Exist");
}
}
i tried many thing but sems nothing to work i dont know whats the problem and i hope for a fix from you.

I just had to set this up myself and I can relate to the frustration.
If you are using an in-memory database to run an integration test you have to remember that there is a lot more going on behind the scenes to load your updated PersistenceUnit (where your database details are defined) than meets the eye. What that error message is telling you is that somewhere in the background, in order for one of your test dependencies to be initialized, it has a transitive dependency on this InitService class. So it is starting up the Spring container, discovers it needs one of these InitService instances, and then finds that it doesn't exist (since we never initialized it). To correct this, we'll need to load your original production SpringBoot configuration, with all of its Beans and settings. (Incidentally, this is extremely expensive processing-wise which is why a lot of developers recommend you just mock your DAO classes rather than hit a real database for the tests).
Now assuming you still want to test your DAO layer without mocking it (I know I did), to initialize a test run using your production starting point, you'll want to use the #SpringBootTest annotation within your test class. What this does is tell your project that you want to initialize using your #SpringBootApplication configuration along with your test.
This can be confirmed as expected usage per this line in the #DataJPATest Javadoc:
If you are looking to load your full application configuration, but
use an embedded database, you should consider #SpringBootTest combined
with #AutoConfigureTestDatabase rather than this annotation.
Don't quote me on this, but I believe that if you use a copy of applications.properties within your src/test/resources folder to define your test PersistentUnit, you do not need to use this #AutoConfigureTestDatabase annotation. I didn't require it but then again, I stuck to the JPA interfaces rather than implement the Spring Data so your mileage may vary.
As a final mention, since this is going to reload your entire application in order to run just one test, processing can bubble out of control quickly. As such, I would recommend using profiles (#Profile and #ActiveProfiles) and configuration classes (#Configuration and #TestConfiguration) to partition your #Bean definitions so that you can better control what gets loaded and when. Partitioning your configurations also has the added benefit of letting you call different component and entity scan commands depending on the profile, which can help better organize your project.
Hope that helps!

Related

Spring Boot Test with Cucumber and Mockito

I recently started to use Cucumber to implement a set of behavior driven tests for a Java project based on Spring Boot. I would like to call REST endpoints of this application using something like REST Assured or a custom REST client and for external systems and database I would like to setup some mock with Mockito, as I have already done with unit tests.
But I didn't find a complete working solution that I can apply to use Mockito beans in my Cucumber steps, for example to simulate a possible response from database queries.
I found a lot of posts of people over the years that had similar problems with different versions of Cucumber/Junit/Spring but I don't understand if it exists a right way to make these tools working together because I didn't a single complete example related to these tools together. Can anyone share experiences (versions/examples) in real world projects using Spring Boot Test, Cucumber and Mockito?
I finally found the solution. You can start the Cucumber test suite with a class like this
import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("bdd")
#ConfigurationParameter(key = PLUGIN_PROPERTY_NAME,
value = "pretty")
#ConfigurationParameter(key = PLUGIN_PROPERTY_NAME,
value = "usage")
#ConfigurationParameter(key = PLUGIN_PROPERTY_NAME,
value = "html:target/cucumber-reports")
#ConfigurationParameter(key = GLUE_PROPERTY_NAME,
value = "myproject.cucumber.glue")
public class RunCucumberTest {
}
In the glue folder you can create a Spring Boot Test that will create the Spring Context and create the bridge between Spring Boot and Cucumber worlds thanks to CucumberContextConfiguration
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import io.cucumber.spring.CucumberContextConfiguration;
import myproject.repository.MyEntityRepository;
#CucumberContextConfiguration
#SpringBootTest
#ActiveProfiles("test")
public class SpringBootTestStarter {
#MockBean
private MyEntityRepository myEntityRepository;
}
Here you can use Mockito MockBean annotation and in the steps related to Cucumber scenarios you can now use this bean as a mock

Can an Intellij Scratch file be used to query via a JpaRepository interface?

Intellij has a useful feature called a "Scratch File" that allows you to try adhoc Java/Kotlin code against your module(s). I'd like to use this in a Spring/Hibernate project.
Is it possible to induce Spring to create all of the proxies and autowired bits necessary such that a JpaRepository interface can be used for adhoc method calls (and thus, try out specific database queries)?
For example:
import org.springframework.data.jpa.repository.JpaRepository
import java.util.*
interface UserRecordRepository : JpaRepository<UserRecord, UUID> {
fun findByIdAndDeletedIsFalse(id: UUID): UserRecord
...
}
How might I call findByIdAndDeletedIsFalse from a Scratch file?

Odd Spring Boot #Autowired error on a repository NOT due to wrong project structure or missing annotations

I'm asking this question with a risk of having it marked as duplicate, but I honestly don't think it is, so here it goes.
I'm having trouble running a basic Spring Boot application. The error I'm getting is this:
Parameter 0 of constructor in com.example.demo.service.EventService required a bean of type 'com.example.demo.dao.EventRepository' that could not be found.
Now this seems like a pretty common error (and question on SO) that should point the developer to check the following issues:
Most commonly the project structure is wrong (or let's say 'custom') and the bean is not getting scanned because of hierarchy [Questions: this, this, this, this and probably many more]. Solution should be to place the SpringBootApplication in the top package and all the components in its sub-packages so it could scan everything properly or to custom-define the packages that need to be scanned.
The bean was not defined, i.e. there's a missing annotation of type #Service, #Repository etc. so the bean is not being created.
Another reason might be using two different ways of defining beans (as posted here). I'm using purely annotation-style defining, so I think I should be good here.
Also, this question has an answer mentioning to exclude the autoconfiguration of JPA repositories from application.properties file, but I don't have this configuration set.
There were also a couple of questions/answers mentioning issues with dependencies and pom.xml file which fixed this problem, but my pom.xml is a pretty basic file created from Spring Initializr, so again, I don't think this is the solution.
The error message also says:
Consider defining a bean of type 'com.example.demo.dao.EventRepository' in your configuration.
The 'missing bean' is this repository:
package com.example.demo.dao;
import com.example.demo.entity.Event;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface EventRepository extends JpaRepository<Event, Integer> {
}
You can see it has #Repository annotation (although I've created repositories without this annotation before and it worked fine so I don't think this is required, but I added it now just in case this was the issue), it extends JpaRepository so it should be a valid repository and it's inside com.example.demo.dao package.
The class that's autowiring this is a service:
package com.example.demo.service;
import com.example.demo.dao.EventRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class EventService {
EventRepository eventRepository;
#Autowired
public EventService(EventRepository eventRepository) {
this.eventRepository = eventRepository;
}
}
I'll also provide the main application so you can see its package is com.example.demo which is a parent package for both the service and the repository:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
I've also tried rebuilding the project and the infamous "closing and reopening" of IntelliJ, because it was known for sometimes acting stupid in my experience and this would solve it, but not this time.
Also as a side note, I've successfully created these kinds of projects before, so I'm really not sure what's the issue right now.
Am I missing something obvious here? What else can I check?
EDIT:
Here's the entity class as well (generated by an IDE tool):
package com.example.demo.entity;
import javax.persistence.*;
import java.sql.Timestamp;
import java.util.Objects;
#Entity
public class Event {
private int id;
private String name;
private Timestamp dateFrom;
private Timestamp dateTo;
// getters & setters abstracted
}
Turns out it was an issue with pom.xml after all.
I've added the JPA dependency later and accidentally added the wrong one. My pom.xml had
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
instead of
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Apparently the IDE tool used for generating entities from tables was missing javax.persistence so it added that jar manually through lib folder. Everything looked fine to IntelliJ, but something was messed between dependencies.
Anyway, I changed the dependency in pom.xml and removed the extra jar added. Now everything works fine.

Unit testing Spring Boot application Service layer

I'm a bit confused about the test capabilities and utilities provided by Spring Boot.
I'm using spring-boot-starter-test in my project and I'd like to unit test my services without the database connection
At the moment I'm using #WebMvcTest for contoller test suites and #SpringBootTest for all the other test classes.
But I read somewhere that #SpringBootTest is meant to be used only in integration tests...
Reading documentation I didn't understood what's the suggested approach for services. Should I only test them in integration with repos?
UPDATE
That's an excerpt of a test class for one of my services:
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#SpringBootTest
internal class SignupServiceTest(
#Autowired val signupService: SignupService
) {
#MockkBean
lateinit var userRepository: UserRepository
#Test
fun `should return exception if username already used`() {
every { userRepository.findByUsername("registered-user") } returns fakeUser(username = "registered-user")
assertThatThrownBy {
signupService.createNewAccount(fakeSignupForm(username = "registered-user"))
}.isExactlyInstanceOf(UsernameNotAvailableException::class.java)
}
// ... other tests
}
Using #SpringBootTest for unit tests is a bit of a overkill. Because this would boot up the whole application context.
To test individual (service) classes I would go with #RunWith(MockitoJUnitRunner.class) and instead of #Autowired and #MockBean use #Mock and #InjectMocks(If you use constructor injection, you wouldn't have to use this. which would be the better option)
You could still use #Autowired with #ContextConfiguration and load specific classes(if there are not too many transitive dependencies)
If you do not want to use mocks, then you can use embedded databases and use #DataMongoTest or #DataJpaTest and use Springboot testing capabilities.
Keep it simple....
You should favor implementing unit tests to test your business logic (tests running without Spring, plain JUnit tests) over integration tests (tests starting a Spring container, #SpringBootTest) as they are more lightweight and give you feedback a lot faster.
Quote from Spring Boot doc
One of the major advantages of dependency injection is that it should make your code easier to unit test. You can instantiate objects by using the new operator without even involving Spring. You can also use mock objects instead of real dependencies.
Often, you need to move beyond unit testing and start integration testing (with a Spring ApplicationContext). It is useful to be able to perform integration testing without requiring deployment of your application or needing to connect to other infrastructure.
try to mock the calls to database using mockito, or use h2 database for the tests
I was previously using #SpringBootTest as well then realized it was also trying to connect to my database, which should not be needed since it's a simple service test and all dependencies are mocked. After a bit of research I found this solution works quite well. Also note now my spring properties were not being injected so I used #Spy to create a pojo property object with some test values.
#ExtendWith(MockitoExtension.class)
public class MyServiceTest {
/**
* This is the bean under test as it is not a mock
*/
#InjectMocks
private MyService myService;
#Mock
private OtherService otherService;
#Spy
private MyServiceProperties properties = mockProperties();
#BeforeEach
public void configureMocks() {
given(this.otherService.getData(any())).willReturn(mockDataResponse());
}
#Test
void testMyServiceReport_Success() {
myService.runReport();
//assert response as needed
verify(otherService, times(1)).getData(any());
}
Also here is some help with the imports which can sometimes be confusing:
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.BDDMockito.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.times;
import static org.mockito.BDDMockito.verify;

Springboot build not working because of test configuration

I have started a spring boot project using start.spring.io.
But I am getting this error-
I have read various articles on the internet about this issue and they all say about putting my tests in the same package as my Main class.
But I already have the same.
Could you point out what is wrong with my configuration?
The exception is pretty clear: You are missing a configuration for your spring context. What you need to do is to add the configuration classes for your context like so:
#SpringBootTest(classes = { TestConfiguration.class })
whereas your TestConfiguration class must be annotated with
#Configuration
and/or
#EnableAutoConfiguration
There you can add configurations to your liking. You can of course also use your DatabaseApplication class as Configuration although Im wouldn't recommend that.
The search algorithm works up from the package that contains the test until it finds a #SpringBootApplication or #SpringBootConfiguration annotated class. As long as you’ve structure your code in a sensible way your main configuration is usually found.
Make Sure your DatabaseApplication class is annotated with #SpringBootApplication .

Resources