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.
Related
I want to make a database call before every method within my Spring application annotated with #Transactional started executing transaction.
There are few requirements for this:
This database call has to be part of the actual transaction that is about to begin.
The database connection used for the Transaction has to be same to be used for this database call and should setup some database data before 'real' transaction begins.
Is there something that Spring supports to achieve this goal ? One way I am thinking is to write own Aspect cloning more or less all Transactional code as is. Other way is to write Aspect. Not sure if there are more ways.
I'm trying to unit (integration) test a method annotated with Spring's #Async.
The test sets up some data in in-memory h2 database, then runs the asynchronous method. Asynchronous code does not see test data :O
Removing #Async fixes the problem.
Any help? :)
I had the same error. The solution was quite simple for me: I did not put a COMMIT; to the end of my data_init-h2.sql
I presume you did not put this either. If you think about it this is quite logical. Your main thread fires up a transaction but does not actually commit it to h2. Spring fires up another thread and the #Async method is run there in a separate transaction.
Because of the lack of commit you do not see the data changes on this other thread. On the main thread you can see your data changes even before they are committed as you are in that transaction.
The transaction isn't propagated like it was before your #Async.
#Async and #Transactional: not working
Your test could commit the data and delete it either side of the test, removing Spring's automated rollback inside test #Transactionals.
You could create a default-access method that the async method calls into, that your test could also call direct, though you would no longer be testing the Async behaviour.
There's likely a nicer spring implementation that supports what you need, making the transaction available but I don't have it.
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.
I would like to create some data in #BeforeClass and use them in my #Test method.
After all tests are finished (failed or succeeded), I would like to rollback the data.
Can this be achieved using the annotations #BeforeClass, #Transactional, without having to clean up the data explicitly?
We had a similar problem here. Our solution was to give each test class an embedded H2 database (just takes a couple of seconds to setup the first one; after that, it's not really noticeable anymore).
That allowed us to load any kind of test data into the database, no need to clean that up after all tests have run.
Each test still gets its own transaction, so after each individual test, the per-class database is rolled back to the original state.
To debug tests, we would annotate the individual test with #Transactional(rollback=false), so we could look at the database with an SQL tool.
Another test would examine all tests classes, looking for this annotation to make sure no one accidentally commits it.
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.