Spring boot testcase is failing due to (ReactiveWebApplicationContext must be an instance of interface ConfigurableWebApplicationContext) - spring

I have created new spring boot project with version springBootVersion = '2.0.0.BUILD-SNAPSHOT'. When I start my application it's running without any errors, where as test case is failing with error
[org.springframework.boot.context.embedded.ReactiveWebApplicationContext]
must be an instance of interface
org.springframework.web.context.ConfigurableWebApplicationContext
This is my gradle dependency for test.
testCompile('org.springframework.boot:spring-boot-starter-test')
here is test case
#EnableAutoConfiguration
#RunWith(SpringRunner.class)
#SpringBootTest(classes=MarketDataApplication.class)
public class MarketDataApplicationTests {
#Test
public void contextLoads() {
}
}
Am I missing any dependency?

Related

How to exclude Mongo spring data configuration only for tests

I am doing a simple sample project with Spring boot and data.
#Configuration
public class MongoConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MongoConfig.class);
#Value("${mongo.uri}")
private String mongoUri;
public #Bean MongoClient mongoClient() {
LOGGER.info(" creating connection with mongodb with uri [{}] ", mongoUri);
return MongoClients.create(mongoUri);
}
}
This works fine and connects to mongo on startup. However, the tests also pick this up in autoscan. What is the best practice to make sure that mongo config gets excluded for tests?
If I add #WebMvcTest to the tests, it works. But not all tests will be mvc tests. I might be testing a utility class.
If I try using profiles, it gives my an error java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes: ...MongoConfig
#SpringBootTest
#ActiveProfiles("test")
class ApplicationTests {
#Test
void contextLoads() {
}
}
Please tell me a repeatable practice as I will be using it for all my tests.
The simplest way of doing it is to exclude your configuration bean when your test profile is active
#Profile("!test")
#Configuration
public class MongoConfig {
...
}
Here you tell to the BeanFactory to not create this bean if the profile test is present
Ref: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Profile.html

Integration Testing With #DataJpaTest

I have this test in my project:
#DataJpaTest
#SpringBootTest
#TestPropertySource(locations = "classpath:local-configuration.properties")
public class CanPixaRepositoryTest {
#Autowired
private CanPixaRepository canPixaRepository;
public void setUp() throws Exception {
}
#Test
public void testAll() {
canPixaRepository].getAvui("fqs");
}
}
local-configuration.properties:
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
but when I run the test, canPixaRepositoryRepository is null
For Spring boot applications, the simplest approach is using #DataJpaTest with H2 to test your repositories if you are using JPA and Spring Data JPA.
Add h2 dependency into your test scope. Spring Boot will auto-configure it and use it to replace the runtime DataSource in the testing phase.
Annotate your tests with #DataJpaTest. Then the EntityManager, your repositories, and a test-purpose TestEntityManager are available in the Spring Application Context.
Check my example here.
(Spring 5/Spring Boot 2 added Junit 5 support, it does not require the #Runwith or #Extendwith if you are using Junit 5 integration, the DataJpaTest itself is a meta-annotation, before Spring 2.4, to enable Junit5, you have to exclude JUnit 4 from spring-boot-test and add JUnit 5 manually. In the upcoming Spring Boot 2.4, JUnit 5 is the default test runner)
#SpringBootTest annotation is used to setup the entire application context while the #DataJpaTest will setup the application context so that you could test your jpa related code, it will setup a slice of your application context for this specific use case .So there is no need to use the #SpringBootTest annotation with #DataJpaTest, use it like :
#ExtendWith(SpringExtension.class)
#DataJpaTest
#TestPropertySource(locations = "classpath:local-configuration.properties")
public class CanPixaRepositoryTest {
#Autowired
private CanPixaRepository canPixaRepository;
public void setUp() throws Exception {
}
#Test
public void testAll() {
canPixaRepository.getAvui("fqs");
}
}
Since SpringBoot 2.1 you don't have to provide the #ExtendWithannotation to tell Junit to enable spring support as it is already provided with the annotations like #SpringBootTest and #DataJpaTest.

Test Spring Data Repository in a project without a Spring Boot Application main class

I have a small project that does not contain a class to run a Spring Boot Application. In that class I only have some configuration and some repositories. I would like to test those repositories inside the small project.
For that, I have the following:
#SpringBootTest
#DataJpaTest
public class TaskRepositoryTest extends AbstractTestNGSpringContextTests {
#Autowired
private TaskRepository taskRepository;
#Test
public void test() {
taskRepository.save(new Task("open"));
}
}
But I get the following error
Caused by: java.lang.NoSuchMethodError: org.springframework.boot.jdbc.DataSourceBuilder.findType(Ljava/lang/ClassLoader;)Ljava/lang/Class;
Any idea what I have to do?
This works for me with Spring Boot 2.0.3, H2 and latest RELEASE testng:
#EnableAutoConfiguration
#ContextConfiguration(classes = TaskRepository.class)
#DataJpaTest
public class TaskTest extends AbstractTestNGSpringContextTests {
#Autowired
private TaskRepository taskRepository;
#Test
public void test() {
taskRepository.save(new Task("open"));
}
}
LE:
In the previous version of the answer I've used #SpringBootTest #DataJpaTest but that seems to be the wrong way to do it.
The following message would appear:
[main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Neither #ContextConfiguration nor #ContextHierarchy found for test class [one.adf.springwithoutapp.TaskTest], using SpringBootContextLoader
Using #ContextConfiguration with #DataJpaTest removes that warning and IntelliJ doesn't mark the mocked taskRepository as Could not autowire. No beans of 'TaskRepository' type found.

How do I run a spring-boot-rest application from a different module eg: in CI build via Maven?

|--Integration tests
|--Spring boot rest application
I have two modules,
Spring boot application is where I have the end points,
it runs on its own embedded tomcat, I want to be able to run it as a part of Integration test's maven build and run integration tests on it.
My question is, is there a way to run spring boot application from a different module via maven?
On Spring boot's website I can only see an example of running a spring-boot application through its own pom by using spring-boot-maven-plugin, but not by running the application as a part of different module by specifiying a jar file with in the execution.
Yes, there are several ways to do what you ask, for example:
use the #SpringBootTest annotation on your test classes (since Spring Boot 1.4);
programmatically start the Spring Boot application from within your test.
The first is my favorite one and the simpler one as well but it only works in the context of unit tests, of course. Here's an example.
Let's assume that you have a class named Application annotated with #SpringBootApplication in your REST module. You can test the endpoints by just defining a test like this inside your Integration test module:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class, properties = {"my.overriden.property=true"} )
public class RestEndpointTest
{
// ...
}
By doing so, the entire context of the application will start. You can then further configure your test depending on your needs, also overriding some properties (see my.overridden.property).
Alternatively, you can define your own configuration inside the test module, referencing any required class from the other module, for example:
#Configuration
#ComponentScan(basePackageClasses = {BaseClass.class})
#EnableJpaRepositories
#EntityScan
#EnableAutoConfiguration
public class SupportConfiguration
{
#Bean
public ARequiredBean bean()
{
return new ARequiredBean();
}
// etc...
}
and the using it just like you would do with any other context:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = SupportConfiguration.class)
public class CustomTest
{
// ...
}
The other method would be to programmatically start an instance of your REST application, with something like this:
public static void main(String[] args) throws IOException
{
try (ConfigurableApplicationContext context = SpringApplication.run(Application.class, args))
{
log.info("Server Started. Press <Enter> to shutdown...");
context.registerShutdownHook();
BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in));
inReader.readLine();
log.info("Closing application context...");
context.stop();
}
log.info("Context closed, shutting down. Bye.");
System.exit(0);
}

How to exclude/disable a specific auto-configuration in Spring boot 1.4.0 for #DataJpaTest?

I am using the #DataJpaTest from Spring for my test which will then use H2 as in memory database as described here . I'm also using Flyway for production. However once the test starts FLyway kicks in and reads the SQL file. How can I exclude the FlywayAutoConfiguration and keep the rest as described here in spring documentation in order to let Hibernate create the tables in H2 for me?
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private MyRepository triggerRepository;
}
Have you tried the #OverrideAutoConfiguration annotation?
It says it "can be used to override #EnableAutoConfiguration".
I'm assuming that from there you can somehow exclude FlywayAutoConfiguration
like so:
#EnableAutoConfiguration(exclude=FlywayAutoConfiguration.class)
Adding the dependency on an in-memory database to my build.gradle
e.g. testRuntime "com.h2database:h2:1.4.194"
And adding flyway.enabled=false to application.properties in src/test/resources worked for me.
I am converting an old JDBC app into a spring-data-jpa app and I'm working on the first tests now. I kept seeing a security module instantiation error from spring-boot as it tried to bootstrap the security setup, even though #DataJpaTest should theoretically be excluding it.
My problem with the security module probably stems from the pre-existing implementation which I inherited using PropertySourcesPlaceholderConfigurer (via my PropertySpringConfig import below)
Following the docs here:
http://docs.spring.io/spring-boot/docs/1.4.x/reference/htmlsingle/#test-auto-configuration
and your comments on #LiviaMorunianu's answer, I managed to work my way past every spring-boot exception and get JUnit to run with an auto-configured embedded DB.
My main/production spring-boot bootstrap class bootstraps everything including the stuff I want to exclude from my tests. So instead of using #DataJpaTest, I copied much of what it is doing, using #Import to bring in the centralized configurations that every test / live setup will use.
I also had issues because of the package structure I use, since initially I was running the test which was based in com.mycompany.repositories and it didn't find the entities in com.mycompany.entities.
Below are the relevant classes.
JUnit Test
#RunWith(SpringRunner.class)
#Transactional
#Import({TestConfiguration.class, LiveConfiguration.class})
public class ForecastRepositoryTests {
#Autowired
ForecastRepository repository;
Forecast forecast;
#Before
public void setUp() {
forecast = createDummyForecast(TEST_NAME, 12345L);
}
#Test
public void testFindSavedForecastById() {
forecast = repository.save(forecast);
assertThat(repository.findOne(forecast.getId()), is(forecast));
}
Live Configuration
#Configuration
#EnableJpaRepositories(basePackages = {"com.mycompany.repository"})
#EntityScan(basePackages = {"com.mycompany.entity"})
#Import({PropertySpringConfig.class})
public class LiveConfiguration {}
Test Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestConfiguration {
// lots of bean definitions...
}
PropertySpringConfig
#Configuration
public class PropertySpringConfig {
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
throws IOException {
return new CorePropertySourcesPlaceholderConfigurer(
System.getProperties());
}
}
In my particular case, i needed to disable the FlywayDB on in-memory integration tests. These are using a set of spring annotations for auto-configuring a limited applicationContext.
#ImportAutoConfiguration(value = TestConfig.class, exclude = FlywayAutoConfiguration.class)
the exclude could effectively further limit the set of beans initiated for this test
I had the same problem with my DbUnit tests defined in Spock test classes. In my case I was able to disable the Flyway migration and managed to initialize the H2 test database tables like this:
#SpringBootTest(classes = MyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = ["flyway.enabled=false", "spring.datasource.schema=db/migration/h2/V1__init.sql"])
I added this annotation to my Spock test specification class. Also, I was only able to make it work if I also added the context configuration annotation:
#ContextConfiguration(classes = MyApplication.class)
I resolved the same issue by excluding the autoconfiguration from my application definition, i.e.
#SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
you can also sue the following annotation:
#RunWith(SpringRunner.class)
#DataJpaTest(excludeAutoConfiguration = {MySqlConfiguration.class, ...})
public class TheClassYouAreUnitTesting {
}
You can just disable it in your test yaml file:
flyway.enabled: false

Resources