I have Spring Boot application with configuration:
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled=true)
#EnableJpaRepositories(basePackages = "com.site.data.repository")
#EntityScan(basePackages = "com.site.data.entity")
#ComponentScan(basePackages = "com.*")
#SpringBootApplication
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
And in resources folder there is application.properties file:
spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...
spring.datasource.driverClassName=...
#...
Problem:
I try to make new class which will add some entries to database. I thought that the best solution is making a JUnit test class. So if anybody wants to feed my database he could simply run this specific test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = WebSecurityConfig.class)
public class DataFeeder {
#Autowired
MyRepository myRepository;
#Test
public void feedDB() {
MyEntity entity = new MyEntity();
myRepository.saveAndFlush(entity);
}
}
But this configuration doesn't work. Of course all repositories work great in project. But during running test I obtain messages that all tables don't exist. For example for SOME_TABLE:
Table "SOME_TABLE" not found; SQL statement:
I saw a lot of tutorials about how to test JpaRepository, but I don't want make test, which add some items and delete it after test end. I simply want save some data in database (but in #Test function)
What is wrong with my configuration?
use #SpringApplicationConfiguration instead of #ContextConfiguration.
this is needed for Spring-boot application tests.
Related
Let's say I'm testing a repository :
#RunWith(SpringRunner.class)
#SpringBootTest
public class UserRepositoryTest {
#Test
(...)
#Test
(...)
}
I'm ok that spring loads other repositories, but I'm not ok it loads the embedded Tomcat, the services, the controllers, ... every time I launch one of these JUnit.
What is the simplest way to achieve this?
I've tried to put some inner #Configuration class with a #ComponentScan limited to my repository package but it didn't work (it was just ignored).
Use the annotation #DataJpaTest instead of #SpringBootTest. It only loads the persistence related part of Spring.
#RunWith(SpringRunner.class)
#DataJpaTest
public class UserRepositoryTest {
#Test
(...)
#Test
(...)
}
You will find a detailed solution here
If you have some usage of JdbcTemplate then take a look to this answer
It looks like there is not one single answer to this question.
Of course, for JPA repositories, Lore answer is the best : use #DataJpaTest (or #JdbcTest for my use case). But be also sure to use "#AutoConfigureTestDatabase(replace = Replace.NONE)" if your test data is in your database and not in some in-memory one.
Also there is a special chapter talking about this in Spring doc :
Spring Boot’s auto-configuration system works well for applications
but can sometimes be a little too much for tests. It often helps to
load only the parts of the configuration that are required to test a
“slice” of your application.
source : https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-tests
But it doesn't show all you can/need to do.
For example, I had a smtpClientService to test.
To test this service, alone in its own layer, I had to do these specific adaptations (if I omit "#AutoConfigureWebClient", I won't get RestTemplateBuilder injected) :
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureWebClient
public class smtpClientServiceTest {
#Autowired
SmtpClientService service;
#Configuration
#Import(SmtpClientConfig.class)
#ComponentScan(basePackageClasses = SmtpClientService.class)
static class TestConfiguration {
}
#Test
public void testSendMessage() {
(...)
}
}
I have a small application that when live, makes a database connection, and stores and persists some data.
I'm currently in the midsts of trying to write some tests, and I'm wanting to completely cut off the database part of the application, and just mock it in the tests.
The Datasource is setup with a configuration class.
#Component
#Configuration
public class DataSourceConfiguration {
#Bean
public DataSource myDataSource() { ... }
}
and a test boostrap that currently looks similar to
#RunWith(SpringRunner.class)
#EnableAutoConfiguration(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class MyTest {
}
When running the test, I can see that Spring is trying to instantiate Hibernate, and a connection to the db, I assume because of my config class. How can I stop Spring from doing this?
No Need to use : #EnableAutoConfiguration
We can narrow down the tests to just the web layer by using #WebMvcTest as below,
#RunWith(SpringRunner.class)
#WebMvcTest
public class WebLayerTest {
#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")));
}
}
Refer how to test spring application with only web or using complete application context loading : https://spring.io/guides/gs/testing-web/ refer mocking example : http://www.lucassaldanha.com/unit-and-integration-tests-in-spring-boot/
I'm testing a REST controller using JUnit 4 and MockMvc. When I've written the test a few weeks ago, everything worked as expected. I've done some modifications in my code but I didn't change the JUnit test. Now, when I'm trying to run my tests, I have the error:
Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/application.properties]
Here is my code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyServerApplication.class)
#SpringBootTest
#Transactional
public class MovieControllerTest {
private MockMvc mockMvc;
#Autowired
private MovieRepository movieRepository;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
// Some tests
}
And my main class:
#SpringBootApplication
public class MyServerApplication{
public static void main(String[] args) {
SpringApplication.run(MyServerApplication.class, args);
}
}
My application.properties file is located in src/main/resources. I didn't move this file, I didn't do anything but add some code in my services and add some properties in my file.
I read SO questions & doc, and tried these solutions:
Check that src/main/resources is still in my test classpath
Add #PropertySource("classpath:application.properties") under the annotations in my test ; it didn't work so I tried to create a src/test/resources with a copy of application.properties inside, as suggested in one post
Add #PropertySource("classpath:application.properties") in the main class instead of the test class
Add #WebAppConfiguration annotation
Add #WebMvcTest annotation
I didn't try all of these solutions at the same time of course, I removed the added code after each failure.
I can still run my code without any issue though, only the test class results in FileNotFoundException.
How to solve this? And why do I have an issue with the test class but everything working fine when I run my server?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = MyServerApplication.class)
#SpringBootTest
#Transactional
public class MovieControllerTest { ... }
This is what you have on your test class. When using #SpringBootTest you shouldn't be using #ContextConfiguration (see testing chapter of the Spring Boot Reference Guide).
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#Transactional
public class MovieControllerTest { ... }
I would also suggest you use Spring Boot for testing instead of trying to do things manually. For mock mvc testing Spring Boot applications there are special slices and setup already done for you.
To enable this add #AutoConfigureMockMvc to your test and put #Autowired on the MockMvc field (and remove the setup in your #Before method).
I have a standard spring-boot app and I want to use MS SQL database for the production environment, whereas for integration tests I'd like to use h2 databse. The problem is that I wasn't able to find out, how to override the default application.properties file. Even though I was trying to follow some tutorials, I didn't come up with the right solution...maybe I'm just missing something...
The main class:
#SpringBootApplication
#EnableTransactionManagement
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication .class, args);
}
}
and the class with tests:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
#WebIntegrationTest
public class MessageControllerTest {
#Autowired
MessageRepository messageRepository;
...
...
...
#Test
public void testSomething(){
...
...
...
...
}
}
So the question is, how to force the spring-boot to use application-test.properties file when running the tests, instead of application.properties, which should be used during the run time.
I tried for example to replace #WebIntegrationTest annotation with #TestPropertySource(locations="classpath:application-test.properties"), but this results in java.lang.IllegalStateException: Failed to load ApplicationContext.
Assuming you have a application-test.properties file in your app.
I do it in two ways :
1.CLI JVM Args
mvn spring-boot:run -Drun.jvmArguments="-Dspring.profiles.active=test
add the application-test.properties as an active profile.
add the spring.profiles.active=test in the application.properties and it will load your application-test.properties file.
As you pointed to in your answer annotate a class test with a specific active profile ( which is not suitable when having a large test classes i think ) #ActiveProfiles("test")
Actually it was pretty easy...after several hours of trying, I've realized that I just needed to annotate my test class with #ActiveProfiles("test") annotation.
#ActiveProfiles("test")
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
#WebIntegrationTest
public class MessageControllerTest {
#Autowired
MessageRepository messageRepository;
...
...
...
#Test
public void testSomething(){
...
...
...
...
}
}
I have datasource defined in my application.properties as Oracle database and that's ok, the controller & repository work fine, I can persist entities and fetch database records.
I have integration tests written. Before I connected my app with database I created some objects and persisted them in #PostConstruct method - and that was ok. But now, when I connected everything with database, my tests try to fetch records from the table which is pretty large.
I think that's due to my application.properties file in which defined datasource is Oracle database.
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:#blabla
spring.datasource.username=blabla
spring.datasource.password=blabla
spring.jpa.hibernate.ddl-auto=none
spring.jpa.generate-ddl=false
I want to carry on tests using some in-memory HSQL, not real database. But I still want my controller and repository to use the real one. How can I do it? Is there any possibility to add second datasource in application.properties? Or maybe an easier solution?
In Spring 4 you have #Profile annotation so you can use its advantage.
Create another like application-test.properties file with it's own properties.
Create configuration for your tests:
#Configuration
#Profile("test")
public class TestConfiguration {
....
}
Then annotate your class with #ActiveProfiles annotation:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#ActiveProfiles("test")
public class TestRepository {
...
}
There are many ways to achieve this, one way is to use Spring profiles. The test profile would use a different properties file than the production one.
Spring has org.springframework.mock.jndi.SimpleNamingContextBuilder package that allows you to bind the dataSource programatically.
Sample Test class that I use:
public class MockJNDIContext {
#BeforeClass
public static void setUpClass() throws Exception {
SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();//Use your own Connection Pool DS here as you require
ds.setURL("jdbc:oracle:thin:#10.xxx.xxx.xx:9999:SID");
ds.setUser("USER");
ds.setPassword("PASSWORD");
//Bind it to the JNDI you need
builder.bind("java:comp/env/jdbc/MY/APP", ds);
}
#Test
public void test(){
System.out.println("JNDI Initialized");
}
}
Suite Class:
#RunWith(Suite.class)
#Suite.SuiteClasses({
MockJNDIContext.class,
InitializeTestConfig.class
})
public class ServiceSuite{
}
May be this helps? If you are trying to load from one more application.props, use one more class (InitializeTestConfig.class) that initializes and passes the DS args and add to suite as mentioned above and try?