I am using Spring 3.2, Hibernate and JUnit 4.
My Dao class is as follows:
#Transactional public class SomeDaoImpl implements SomeDao {
The update operations on this work if executed directly from web application. However, I am seeing that junit integration tests that exercise the update methods do not actually persist the changes. Is something rolling the transactions back when junit methods are executed?
By reference, transactions are not persisted in test contexts in Spring. As mentioned, although unusual, if you still need to do so you can use #TransactionConfiguration and #Rollback to change the default behavior.
DAOs should not be transactional. How can a DAO know if it should participate in a larger transaction?
Services ought to own transactions in the typical Spring layered architecture.
It's typical to run your unit tests for databases in such a way that they do roll back. You don't want your tests to alter the database, unless you've set up a test database that you can drop and recreate at will.
The question ought to be: How do your tests, as written, commit the transaction? If you never commit, you'll never see the records.
From the "Testing" section of the docs, you can use the
#Rollback(false)
annotation if you don't want SpringJUnit4ClassRunner to roll back your transactions.
Related
How to write a proper test case for controller, service and Dao in spring boot using junit 5 with clear explanation
Spring Boot has a concept of test slices. This type of test configuration will setup only a part of your application and thus making tests:
less likely to break on not-related change,
faster in comparison to configuring all application services (using #SpringBootTest annotation).
For example #JsonTest slice will configure ObjectMapper (and some test utilities for JSON) in the same way as it would happen on production.
Anyway, to your mentioned types:
DAO - use #DataJpaTest slice - it will configure Hibernate with in-memory database and load all your entities and repositories.
Controllers - use #WebMvcTest(YourController.class) slice - it will load only configuration for Spring MVC, advices and your controller. You will be responsible to deal with dependencies of that controller.
Services - pretty much depends on what is your service doing. I prefer using slices also for services depending on Spring-configured beans but your test can also be a very simple standard [j]unit test with all dependencies mocked away. - Depending on the compromise you want to make.
This does not change with the fifth version of junit. The only difference is that you no longer need to annotate your tests with #RunWith(SpringRunner.class).
I've been working with Spring and Hibernate for about two years. Recently I have also been working on testing. Now I'm not quite sure if I understood everything correctly. Do I understand correctly that the following methods exist? **If I make wrong assumptions, please correct me!
Method 1:
Situation: The test class is annotated with #Transactional. The test data is created manually in an #BeforeEach method and stored in a repository.
Advantages: Through #Transactional annotation, all (BeforeEach, Test-Method, AfterEach) methods are executed in one transaction, which can be undone directly by rollback and therefore no emptying of the database is necessary.
Disadvantages: Since everything is carried out in one transaction and canceled directly by rollback, the data never ends up correctly in the database? Perhaps errors would occur during a commit? This means that the test does not reflect a real situation.
Method 2:
Situation: The test class has no #Transactional annotation. The test data is created and stored in an #BeforeEach method.
Advantages: Since the #Transactional annotation is missing, all calls of the service or controller are executed in a separate transaction, reflecting a real situation.
Disadvantages: Since everything is executed in separate transactions, the database must be completely emptied manually after each test (disable constraints and empty each table).
I have another question, but it's more subjective Do you like the initialization of test data using the #BeforeEach method and manual creation of objects and saving via repository or SQL scripts in #Sql annotation better? Initializing via SQL scripts feels faster in my opinion.
I have a Spring boot application initially setting on MySQL, so far so good. However now I am trying to create more unit test for JPA / DAO layer with H2 database.
I see several online demo that in Spring it is common practice to have an applicationContext-test for testing context setting.
Is it still good practice in Spring boot 1.4?
#SpringBootApplication(scanBasePackages = {...})
public class ApplicationTest extends SpringBootServeltIntializer{
....
}
As currently there is no separate xml file holding context for testing, is above looks like a good solution? And also is there performance impact that when the application starts all context for testing are also need to loaded in memory?
Also does that mean I need to create an application.properties in test sources? Spring boot has a lot of implicit process behind, but I cannot find much texts explain about the DAO layer setting for test in Spring Boot, so any guideline is appreciated.
My preference is to not use Spring for JUnit testing at all.
JUnit tests, by definition, should be about unit testing individual classes. Spring is a DI engine for satisfying dependencies. Using the real dependencies breaks the idea of a unit test; for those I manually inject mocks.
I do that to restrict the tests to individual classes. I find that creating the Spring factory and all the application beans takes a long time. I don't want to pay that price when I have a lot of unit tests. Keeping Spring out of the mix makes my tests run faster.
I have problem with unit tests for persistance stuff written in spring data jpa.
For particular repositories I have a unit tests to be sure that everything works correctly. Also I have a integration tests. Each tests are passed when I run it for particular test classes. But when i run a whole package of tests I got a lot of faliures because I have records inserted into DB from previous tests.
Of course in each test classes I can add #After method to clean each data but I would like to ask that it posible to clean all data from DB before run tests from particular test classes without adding #After method?
Best Regards.
Use Spring's transactional test support to ensure that database changes are rolled back after each test:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#testcontext-tx
One common issue in tests that access a real database is their effect
on the state of the persistence store. Even when you’re using a
development database, changes to the state may affect future tests.
Also, many operations — such as inserting or modifying persistent
data — cannot be performed (or verified) outside a transaction.
The TestContext framework addresses this issue. By default, the
framework will create and roll back a transaction for each test.
Is it possible to register some kind of callback with a JTA transaction in a Spring application?
I've got some mock services that are standing in for remote services that belong to another application that's normally accessed using Spring's HttpInvoker. These mock services model data in-memory in a trivial fashion using Maps and the like.
The Unit tests don't necessarily know which of these services might get used; the service the test case is targetting might use them behind the scenes.
The unit tests are transactional, and Spring's SpringJUnit4ClassRunner will rollback the transaction after each test, meaning that the state fo our unit test database is preserved between tests.
How can I rollback the state of this custom in-memory service implementation? If there was a way of finding out if there's a transaction currently going on, then I was hoping there'd be a way of registering a callback with the TransactionManager to be executed before the transaction is completed.
I don't think it's a good idea to clean up test mock in such an implicit way - tests usually perform cleanup explicitly.
However, if you really want, take a look at TransactionSynchronizationManager.registerSynchronization().