what is the usage of #DataJpaTest annotation when testing ?
do we need it with every db connecting test?
the test is working even without the annotation
#RunWith(SpringRunner.class)
#DataJpaTest
why #DataJpaTest is used why it has used and when to use it?
By default, #DataJpaTest will configure an in-memory embedded database, scan for #Entity classes and configure Spring Data JPA repositories. It is also transactional and rollback at the end of each test. If we wanna disable transaction management, we can use:
#Transactional(propagation = Propagation.NOT_SUPPORTED)
We can also inject a TestEntityManager bean specifically designed for tests which is an alternative to the JPA EntityManager.
#Autowired
private TestEntityManager entityManager;
Hence, our Test Class should be similar to:
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyJPAUnitTest extends SpringJpaUnitTestApplicationTests {
#Autowired
private TestEntityManager entityManager;
#Autowired
CustomerRepository repository;
#Test
public void testExample() {...}
}
More details here: https://grokonez.com/testing/datajpatest-with-spring-boot
Use #DataJpaTest annotation
allows you to test domain logic so you can check JPA mappings and you can check queries
It also configures Hibernate, Spring Data and an in-memory database.
You can override the in-memory database if you want to reuse a real one.
It also provides access to a TestEntityManager bean. This is an alternative to the regular entity manager that just provides some
convenience methods that you often want to use in your tests
Related
Can you please explain when to use below annotations and when not to use those. I am pretty new to testing frameworks and confused with all the answers in the web.
#Mock
private Resource resource;
#MockBean
private Resource resource;
#InjectMock
private ProductService productService;
#AutoWired
Private ProductRepository productRepo;
#Mock
Used to make Mockito create a mock object.
#InjectMock
When you want Mockito to create an instance of an object and use the mocks annotated with #Mock as its dependencies.
#AutoWired
Used when you want to autowire a bean from the spring context, works exactly the same as in normal code but can only be used in tests that actually creates an application context, such as tests annotated with #WebMvcTest or #SpringBootTest.
#MockBean
Can be used to add mock objects to the Spring application context. The mock will replace any existing bean of the same type in the application context. If no bean of the same type is defined, a new one will be added. Often used together with #SpringBootTest
So normally you either:
Use #Mock and #InjectMocks for running tests without a spring
context, this is preferred as it's much faster.
Use #SpringBootTest or #SpringMvcTest to start a spring context together with #MockBean to create mock objects and #Autowired to get an instance of class you want to test, the mockeans will be used for its autowired dependencies. You use this when writing integration tests for code that interact with a database or want to test your REST API.
I have seen multiple threads about it. However, no one really solves my problem.
I have a Spring Boot 2.3 application with the three traditional layers: Controller, Service and DAO. The transactions are declared in my Service layer.
I would like to test my Controller layer using MockMvc, and I want the transactions to rollback at the end of the tests so that they all remain independent. However, I don't want the tests to give the Controller classes an access to the transactional context in order to have the same configuration as in runtime.
I created the following class:
#SpringBootTest
#AutoConfigureMockMvc
public class ApiIT {
#Autowired
private MockMvc mvc;
#Test
void restEndpointTest() {
...
This configuration doesn't rollback the transactions at the end of the tests.
When I annotate the class with #Transactional, they rollback, but the Controller classes can access the transactional context.
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'm testing Spring Boot capabilities as a newbie in this area. I have a simple app with basic dependencies.
sping-boot-starter-parent 1.5.7
sping-boot-starter
sping-boot-starter-data-jpa
sping-boot-starter-test
Then there is simple Application class with #SpringBootApplication annotation.
Then I have a simple DummyService with #Service annotation.
Then I have created a simple test DummyServiceTest with one #Test method and #RunWith(SpringRunner.class) and #SpringBootTest annotations.
#SpringBootTest is the key problem. With spring-boot-starter-data-jpa dependency and this annotation test requires even #DataJpaTest annotation. Without it the framework doesn't solve HibernateJpaAutoConfiguration or DataSource or other injection dependencies even if the test doesn't require using data.
Can I suppress it somehow? I'm not any kind of Spring guru so my guess is that there is some simple configuration to handle this problem.
P.S. Ok, back on trees. Even with #DataJpaTest that test doesn't solve data dependencies. I tried add #AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) and it doesn't work either. I tried add #Transactional with the same result. It's a little bit beyond ridiculous.
If you aren't using JPA yet, then comment out / remove the dependency from build.gradle until you are using JPA. You need to define a datasource and other configuration details before the Hibernate and/or JPA configuration will complete successfully. Every application dependency gets resolved while #SpringApplicationConfiguration code is running, even if your current "hello world" test doesn't require JPA data.
My current unit tests actually have #SpringBootTest commented out. Here's a simplified view of how things are set up and working in my app's JPA related tests:
#RunWith(SpringJUnit4ClassRunner)
#SpringApplicationConfiguration(classes = DaemonApplication)
#ActiveProfiles('local')
//#SpringBootTest
#Transactional
public abstract class AbstractJpaTest extends AbstractTransactionalJUnit4SpringContextTests {
#BeforeTransaction
public void setupData() throws Exception {
deleteFromTables('User', 'User_Session', 'User_Handshake');
}
}
and then
class UserHandshakeRepositoryIntegrationTest extends AbstractJpaTest {
#Autowired UserHandshakeRepoImpl handshakeRepository;
#Test
public void testSave() {
UserHandshake handshake = handshakeRepository.save(new UserHandshake());
assertThat(handshake.getId(), is(notNullValue()));
}
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.