For a test, i have a abstract class.
public abstract class BaseTestClass
private JdbcTemplate jdbcTemplate;
#Autowired
public void setDataSource(DataSource dataSource)
{
this.setJdbcTemplate(new JdbcTemplate(dataSource));
}
...
}
#Transactional
#ContextConfiguration(locations = {"/spring/test/test-dao-context.xml"})
public class TestUser extends BaseTestClass{
...
}
In test-dao-context.xml file, i have my transaction manager and datasource.
SetDataSource is never called, so i get a null pointerException when i try to do a test.
You need to run you test with an appropriate runner which is SpringJUnit4ClassRunner for Spring driven tests. Otherwise nothing will get injected anywhere as there is no Spring Container managing all the instances.
Check Spring Unit Testing for details.
Related
I'm using redis caching and spring boot annotations[#Cacheable and #CahePut],
I made RedisManager transactionAware, which will use the outer transaction[callee of caching layer]
#Bean
public RedisCacheManager cacheManager() {
RedisCacheManager rcm =
RedisCacheManager.builder(redisConnectionFactory())
.cacheDefaults(cacheConfiguration())
.transactionAware()
.build();
return rcm;
}
while testing as below, I'm using embedded redis-:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureTestDatabase
#Transactional
public class RoleServiceImplTest extends TestingProfile {
#Before
public void setup() throws Exception {
//setup server and services
redisServer = new RedisServer(redisPort);
redisServer.start();
}
#Test
public void getUsersForRoleForTemplateRole() {
// call to caching layer methods directly annotated with #Cachable
}
...
Both times [ with and without #Transactional ] spring calls cache.put(key,result) without exception but it only persists values in case of without #Transactional.
Couldn't find much on internet, kudos to any help in advance.
In short just put #Commit or Rollback(false) annotation over your class or test method.
Spring by default rollback every Transaction after the test method.
https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#testcontext-tx
In the TestContext framework, transactions are managed by the TransactionalTestExecutionListener, which is configured by default, even if you do not explicitly declare #TestExecutionListeners on your test class. To enable support for transactions, however, you must configure a PlatformTransactionManager bean in the ApplicationContext that is loaded with #ContextConfiguration semantics (further details are provided later). In addition, you must declare Spring’s #Transactional annotation either at the class or the method level for your tests.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/transaction/TransactionalTestExecutionListener.html
Declarative Rollback and Commit Behavior
By default, test transactions will be automatically rolled back after completion of the test; however, transactional commit and rollback behavior can be configured declaratively via the #Commit and #Rollback annotations at the class level and at the method level.
I have a simple Spring Boot web app, that reads from a database and return a JSON response. I have the following test configuration:
#RunWith(SpringRunner.class)
#SpringBootTest(classes=MyApplication.class, properties={"spring.config.name=myapp"})
#AutoConfigureMockMvc
public class ControllerTests {
#Autowired
private MockMvc mvc;
#MockBean
private ProductRepository productRepo;
#MockBean
private MonitorRepository monitorRepo;
#Before
public void setupMock() {
Mockito.when(productRepo.findProducts(anyString(), anyString()))
.thenReturn(Arrays.asList(dummyProduct()));
}
#Test
public void expectBadRequestWhenNoParamters() throws Exception {
mvc.perform(get("/products"))
.andExpect(status().is(400))
.andExpect(jsonPath("$.advice.status", is("ERROR")));
}
//other tests
}
I have a DataSource bean that is configured in the main configuration of the application. When I run the tests Spring tries to load the context and fails, because the datasource is taken from JNDI. In general I want to avoid creating a datasource for this tests, because I have the repositories mocked.
Is it possible to skip the creation of datasource when running the unit tests?
In memory database for testing is not an option, because my database creation script has a specific structure and cannot be easily executed from classpath:schema.sql
Edit
The datasource is defined in MyApplication.class
#Bean
DataSource dataSource(DatabaseProeprties databaseProps) throws NamingException {
DataSource dataSource = null;
JndiTemplate jndi = new JndiTemplate();
setJndiEnvironment(databaseProps, jndi);
try {
dataSource = jndi.lookup(databaseProps.getName(), DataSource.class);
} catch (NamingException e) {
logger.error("Exception loading JNDI datasource", e);
throw e;
}
return dataSource;
}
Since you are loading configuration class MyApplication.class datasource bean will be created, Try moving datasource in another bean which is not used in a test, make sure all classes loaded for tests are not dependant on datasource. Or In your tests create a config class marked with #TestConfiguration and include it in SpringBootTest(classes=TestConfig.class) mocking data source there like
#Bean
public DataSource dataSource() {
return Mockito.mock(DataSource.class);
}
But this may fail since method call to this mocked datasouce for connection will return null, In that case, you'll have to create an in-memory datasource and then mock jdbcTemplate and rest of dependencies.
Try adding your datasource as a #MockBean too:
#MockBean
private DataSource dataSource
That way Spring will do the replacing logic for you, having the advantage that your production code bean creation won't even be executed (no JNDI lookup).
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/
In my Spring Boot application I access my Hibernate session as shown in this answer: https://stackoverflow.com/a/33881946/272180
Now I also want to access the Hibernate Session in a unit test.
How can I set up the datasource and access the Hibernate Session in a unit test of a Spring Boot application?
When I simply Autowire it, I get org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread.
Autowiring and using a #Service works flawlessly.
My unit-testing class looks like this atm:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = App.class)
#WebIntegrationTest
public class WebTest {
#Autowired
private SessionFactory sessionFactory;
#Autowired
private UserService userService;
#Test
public void testService() {
final List<User> users = userService.getUsers();
// do something with users
// ...
}
}
App.class refers to the class with the main method which is used to run the Spring Boot application.
In fact, the solution was as easy as adding #Transactional to the test-class.
After that I could use the SessionFactory as usual.
I have a Java application based on Spring that uses services. For some reasons, I need to autowire a service that is implemented just for the sake of unit testing. I would like this autowired class to be a Mockito mock, such that I can pass it to all the Mockito methods (when(), etc.). Should I extend or implement some Mockito class?
E.g.
#Profile("test")
#Primary
#Service
public class MockAService implements AService {
public void callMethod(){}
}
Then in the test I have
{
System.setProperty("spring.profiles.active", "test");
}
#Autowired AService aservice;
and in the test method I want to do:
#Test
public void test(){
doNothing().when(aService).callMethod();
}
Just use #Spy and in you #Before method call MockitoAnnotations.initMocks. It will create a spy for your injected services.
Exemple i want to test MyService and it has a dependecy on MyDao. I want MyService to use my mocked dao.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/com/stackoverflow/mokito/exemple/spring.xml"})
public class TestCase {
#Resource
#InjectMocks
private MyService service;
#Resource
#Spy
private MyDao dao;
public void setup() {
MockitoAnnotations.initMocks(this);
}
}
However your spring context is now "dirty". The next test class will use the same spring context and MyService will still use the mock. So don't forget to reset mock in #After
A mock would even be better than a spy if you don't want the service to do anything. By default, calling the function on the mock won't do anything.
With the spy, you have to explicitly call doNothing().
But why do you want to load any Spring context anyway ? Couldn't you mock all the services and test your class in full isolation ?