I know how to configure Spring/JUnit to rollback after each test case.
What I am after is a way to start and roll back one transaction for all test cases.
I am using #BeforeClass to prepare my HSQL DB for several test cases. Then I want to rollback the changes after the end of all test cases in #AfterClass.
What is the best way to achieve this rollback?
Here is my code example:
#BeforeClass
public static void setupDB(){
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:/spring/applicationContext-services-test.xml");
//- get beans and insert some records to the DB
...
}
#AfterClass
public static void cleanUp(){
??? what should go here?
}
Any idea on the best way to do rollback in AfterClass?
Thanks to all..
In case it's acceptable to you to roll back after each test and to use Spring, the following snippet from my project might help you:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/net/sukharevd/shopzilla/model/application-context-dao.xml" })
#TestExecutionListeners(DependencyInjectionTestExecutionListener.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
public class HibernateCategoryDaoTest extends AbstractTransactionalJUnit4SpringContextTests {
You probably don't want to be doing a rollback after the class, but after each test. Tests are not guaranteed to run in the same order each time, so you might get different results. Unit tests should be isolated.
You can use the spring test runner to annotate your class and rollback transactions
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(defaultRollback=true)
public static class YourTestClass {
#Test
#Transactional
public void aTest() {
// do some db stuff that will get rolled back at the end of the test
}
}
In general though you should also try to avoid hitting a real database in unit tests. Tests that hit the database are generally integration level tests (or even more coarse grain tests like acceptance tests). The DBUnit http://www.dbunit.org/ framework is used to stub out databases for unit tests so you dont' need to use a real database.
I managed to solve this issue using just Spring/JUnit (without using DBUnit).
In short, the solution was to call transactionManager.getTransaction(def).setRollbackOnly(); in #BeforeClass.
Let me first explain what I was trying to do.
My main motive was around this flow:
1. Start transaction
2. Insert load test data
3. run several test cases on the same test data
4. rollback test data.
Since I am building my load test data in #BeforeClass, I was looking to rollback in #AfterClass. This seems to be unnecessary as I can simply instruct the transaction to be rollback only in my #BeforeClass!
So here is how I did it:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/spring/applicationContext-services-test.xml")
#TestExecutionListeners(inheritListeners = false, listeners = { SpecialDependencyInjectionTestExcecutionListener.class })
#TransactionConfiguration(defaultRollback = true)
#Transactional
public class loadTest {
...
private static HibernateTransactionManager transactionManager;
...
#BeforeClass
public static void setupDB() {
//- set the transaction to rollback only. We have to get a new transaction for that.
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
transactionManager.getTransaction(def).setRollbackOnly();
...
//- start loading the data using the injected services.
...
}
This helped to rollback at the end of the class.
P.S. The SpecialDependencyInjectionTestExcecutionListener is an extension to DependencyInjectionTestExecutionListener which I used to override beforeTestClass to force the application.context to to be loaded before calling #BeforeClass. Credit goes to Dmitriy in highlighting this Listener which was the hint to solve another problem which i had in my mind.
Thanks to everyone who helped in highlighting and suggestions which collectively led me to this solution.
Dhafir
Let's pretend you weren't using Spring. (Because using Spring the other answers here are better.) Then you would have three choices:
Use dbunit to take care of the data load/cleanup for you. (The site is down at the moment but if you Google it, you can see some tutorials.)
Create manual deletes for the manual updates
Create a rollback point in your database as the first step of setup. Here's how to do so in Oracle.
Related
I have a side project were I'm using Spring Boot, Liquibase and Postgres.
I have the following sequence of tests:
test1();
test2();
test3();
test4();
In those four tests I'm creating the same entity. As I'm not removing the records from the table after each test case, I'm getting the following exception: org.springframework.dao.DataIntegrityViolationException
I want to solve this problem with the following constraints:
I don't want to use the #repository to clean the database.
I don't want to kill the database and create it on each test case because I'm using TestContainers and doing that would increase the time it takes to complete the tests.
In short: How can I remove the records from one or more tables after each test case without 1) using the #repository of each entity and 2) killing and starting the database container on each test case?
The simplest way I found to do this was the following:
Inject a JdbcTemplate instance
#Autowired
private JdbcTemplate jdbcTemplate;
Use the class JdbcTestUtils to delete the records from the tables you need to.
JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
Call this line in the method annotated with #After or #AfterEach in your test class:
#AfterEach
void tearDown() throws DatabaseException {
JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2", "table3");
}
I found this approach in this blog post:
Easy Integration Testing With Testcontainers
Annotate your test class with #DataJpaTest. From the documentation:
By default, tests annotated with #DataJpaTest are transactional and roll back at the end of each test. They also use an embedded in-memory database (replacing any explicit or usually auto-configured DataSource).
For example using Junit4:
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyTest {
//...
}
Using Junit5:
#DataJpaTest
public class MyTest {
//...
}
You could use #Transactional on your test methods. That way, each test method will run inside its own transaction bracket and will be rolled back before the next test method will run.
Of course, this only works if you are not doing anything weird with manual transaction management, and it is reliant on some Spring Boot autoconfiguration magic, so it may not be possible in every use case, but it is generally a highly performant and very simple approach to isolating test cases.
i think this is the most effecient way for postgreSQL. You can make same thing for other db. Just find how to restart tables sequence and execute it
#Autowired
private JdbcTemplate jdbcTemplate;
#AfterEach
public void execute() {
jdbcTemplate.execute("TRUNCATE TABLE users" );
jdbcTemplate.execute("ALTER SEQUENCE users_id_seq RESTART");
}
My personal preference would be:
private static final String CLEAN_TABLES_SQL[] = {
"delete from table1",
"delete from table2",
"delete from table3"
};
#After
public void tearDown() {
for (String query : CLEAN_TABLES_SQL)
{
getJdbcTemplate().execute(query);
}
}
To be able to adopt this approach, you would need to
extend the class with DaoSupport, and set the DataSource in the constructor.
public class Test extends NamedParameterJdbcDaoSupport
public Test(DataSource dataSource)
{
setDataSource(dataSource);
}
I have read quite a few articles/blog/StackOverflow questions, but the confusion regarding Mockito mock and spy still remains. So, I started trying implementing them in a small Spring Boot app. My app has a ProductRepository extending CrudRepository.
Currently I'm testing the repository by mocking ProductRepository as follows
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {RepositoryConfiguration.class})
public class ProductRepositoryMockTest {
#Mock
private ProductRepository productRepository;
#Mock
private Product product;
#Test
public void testMockCreation(){
assertNotNull(product);
assertNotNull(productRepository);
}
#Test
public void testSaveProduct() {
assertThat(product.getId(), is(equalTo(0)));
when(productRepository.save(product)).thenReturn(product);
productRepository.save(product);
//Obviously this will fail as product is not saved to db and hence
//#GeneratedValue won't come to play
//assertThat(product.getId() , is(not(0)));
}
#Test
public void testFindProductById() {
when(productRepository.findOne(product.getId())).thenReturn(product);
assertNotNull(productRepository.findOne(product.getId()));
assertEquals(product, productRepository.findOne(product.getId()));
}
}
The test passes. Is this the right way? I also want to understand how to use #Spy here and Why should I need it? Any specific scenarios related to this is most welcome.
Thanks in advance.
I have taken a look at your tests and there are few things to keep in mind (this is based on my experience so the final call is up to you):
1) Hamcrest - If that is possible i would strongly recommend using Hamcrest for your assert implementations.
First of all it is much more versatile and feature rich than the standard junit assertions.
Second of all you may one day have the need (as i did on one of my projects) to switch from junit to testng for examle.
Having all your assertions based on a xunit-neutral implementation, the switch will not be so painful.
2) Assertions - Instead of assertNull, assertEquals go for the hamcrest's assertThat(String description, T value, Mathcer<T> matcher);
Thanks to that you will get clear error messages when a test breaks.
3) Small tests - In your Repository test.. do not put all the cases in one test.
Try to create many small and simple tests for cases like: findOne.. count.. findAll etc.
Again it will be easier to find the problem when a small test like that breaks.
And if more cases will come you wont end up with a 200+ lines of a test case which is unacceptable
4) Naming - Do not name your tests as.. testXYZ.
It is obvious that these are test methods.
I would recommend using the BDD way of naming: shouldX_whenY_givenZ.
F.e. shouldReturnZeroCount_givenNoEntitiesInTheDatabase
5) Structure - Try to split each of your test implementation in three explicit sections, including comments for best result:
public void should..() throws Exception{
// Arrange
// when().then()
// mock()
// Act
// classUnderTest.process()
// Assert
// assertThat(..)
}
6) Do not split your test classes between Mock / Spy test. HAve one ImplTest.
7) Never mock a class which you are testing. In the worst case scenario use Spy if you have to mock some of the methods of the class under test.
The point of mocking is to isolate the implementation in the class under test, so that only that classes logic is invoked during the test.
Mock only dependencies of the class.
I am trying to use H2 or HSQL for my unit testing. But my application is not of spring and hibernate. It seems most of the references are there only with spring and hibernate for HSQL/H2 in memory db for unit testing.
Can someone point to a right reference where only hsql/h2 is used with junit plainly? Appreciate your time.
I ususally do something like this:
In the #Before method I establish a connection to a memory database, something like this:
#Before
public void setup()
{
this.dbConnection = DriverManager.getConnection("jdbc:hsqldb:mem:testcase;shutdown=true", "sa", null);
}
The connection is stored in an instance variable, so it's available for each test.
Then if all tests share the same tables, I also create those inside the setup() method, otherwise each tests creates its own tables:
#Test
public void foo()
{
Statement stmt = this.dbConnection.createStatement();
stmt.execute("create table foo (id integer)");
this.dbConnection.commit();
... now run the test
}
In the #After method I simplic close the connection which means the in-memory database gets wiped and the next test runs with a clean version:
#After
public void tearDown()
throws Exception
{
dbConnection.disconnect();
}
Sometimes I do need to run unitt-tests agains a real database server (you can't test Postgres or Oracle specific features using HSQLDB or H2). In that case I establish the connection only once for each Testclass instead of once for each test method. I then have methods to drop all objects in order to cleanup the schema.
This can all be put into a little utility class to avoid some of the boilerplate code. Apache's DbUtils can also make life easier as will DbUnit if you want to externalize the test data somehow.
I know I am a little late to the party :-)
I had the same issue a while back and created a JUNIT integration that use the #Rule mechanism to setup an in-memory database for JUnit tests. I found it to be a real easy and good way to be able to test my database integration code. Feedback is more than welcome.
The source code and instructions for use can be found at https://github.com/zapodot/embedded-db-junit
I have a series of unit test where I need to clear a neo4j database. All the tests pass if I run them individually but when I run them all then some fail saying that a particular node could not be found:
org.neo4j.graphdb.NotFoundException: Node[6] not found.
at org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:505)
at org.neo4j.kernel.impl.core.NodeProxy.hasProperty(NodeProxy.java:151)
at org.springframework.data.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.doGetValue(PropertyFieldAccessorFactory.java:85)
at org.springframework.data.neo4j.fieldaccess.ConvertingNodePropertyFieldAccessorFactory$ConvertingNodePropertyFieldAccessor.doGetValue(ConvertingNodePropertyFieldAccessorFactory.java:89)
at org.springframework.data.neo4j.fieldaccess.PropertyFieldAccessorFactory$PropertyFieldAccessor.getValue(PropertyFieldAccessorFactory.java:80)
at org.springframework.data.neo4j.fieldaccess.DefaultEntityState.getValue(DefaultEntityState.java:97)
at org.springframework.data.neo4j.fieldaccess.DetachedEntityState.getValue(DetachedEntityState.java:100)
at org.springframework.data.neo4j.fieldaccess.DetachedEntityState.getValue(DetachedEntityState.java:105)
I have tried this but it didn't solve my problem: Neo4jDatabaseCleaner
What's noticeable is that the tests which have the problem are the one with a relation with properties.
What else could I try?
What about using the ImpermanentGraphDatabase that comes with the Neo4j kernel?
Build/destroy the graph without worrying about cleaning up, etc.
The way we solve this is by having a context aware abstract class that all unit test classes extend. This method contains a before method that clears our all the data in all defined graph repositories.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/applicationContext.xml", "/applicationContext-test.xml" })
public abstract class AbstractTestBase {
#Autowired
private ApplicationContext ctx;
#Before
public void clearAllGraphRepositories() {
Map<String, GraphRepository> graphRepositories = ctx.getBeansOfType(GraphRepository.class);
for (GraphRepository graphRepository : graphRepositories.values()) {
graphRepository.deleteAll();
}
}
}
This can obviously easily be modified to only clear specific repositories, but I'll leave that to you... :-)
One easy way to do this is to run the test trantransactional and roll back after each test?
i'm using this tutorial to set up a test environment:
http://blog.everymansoftware.com/2011/11/development-setup-for-neo4j-and-php.html
the key point is a plugin for neo4j called test-delete-db-extension-1.8.jar
or, in gremlin, you can invoke the command g.clear(); (seems to be the same functionality as the plugins').
In my project, I've used spring, jpa with PostgreSQL DB,
I've lots of table in DB and I need to have Unit testing of all of them.
Is there any framework which just rollback all the transactions after each test finished so every test will have fresh/same DB data to Test. And this way after all Test executions, data of DB schema would be as it is.
Any suggestion for this?
I've some idea of DBUnit but in that I need to write .xml files for every input data for every test and need to insert data in setup() and clear/remove data in tearDown(), but doesn't seems better strategy to me.
Any suggestion is appreciated.
Thanks.
As #Ryan indicates .... the Testing section of the Spring Reference manual should be consulted.
Some startup tips...
We've handled this using Spring's AbstractTransactionalJUnit4SpringContextTests.
For example, we define an abstract superclass:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("file:WebContent/WEB-INF/testconfig/test-web-application-config.xml")
#TransactionConfiguration()
#Transactional
public abstract class OurAbstractTransactionalSpringContextTest extends AbstractTransactionalJUnit4SpringContextTests {
}
And then individual subclasses which need additional context get defined as:
#ContextConfiguration("classpath:path/to/config/ConfigForTestCase.xml")
public class TestOurFunction extends OurAbstractTransactionalSpringContextTest {
#Test
public void testOurMethod() {
}
}
Note that:
Not all test classes need additional context for them, skip the #ContextConfiguration on the particular subclass.
We execute via ant and use the forkmode="perBatch" attribute on the junit task. That ensures all tests run with the same context configuration (saves from reloading the Spring context for each test). You can use the #DirtiesContext to indicate that the context should be refreshed after a method/class.
mark each method with the #Test annotation. The Spring framework doesn't pick up methods using Junit's public void testXXX() convention.
Is there any framework which just rollback all the transactions after each test finished so every test will have fresh/same DB data to Test. And this way after all Test executions, data of DB schema would be as it is.
From my other answer posted earlier in the day, yes, this is possible using DbUnit. (Based on your edit, you don't need this; the subsequent section of my answer addresses why I use DbUnit, and when I wouldn't use it).
The following code snippet demonstrates how the setup of every test is performed:
#Before
public void setUp() throws Exception
{
logger.info("Performing the setup of test {}", testName.getMethodName());
IDatabaseConnection connection = null;
try
{
connection = getConnection();
IDataSet dataSet = getDataSet();
//The following line cleans up all DbUnit recognized tables and inserts and test data before every test.
DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
}
finally
{
// Closes the connection as the persistence layer gets it's connection from elsewhere
connection.close();
}
}
private IDatabaseConnection getConnection() throws Exception
{
#SuppressWarnings({ "rawtypes", "unused" })
Class driverClass = Class.forName("org.apache.derby.jdbc.ClientDriver");
Connection jdbcConnection = DriverManager.getConnection(jdbcURL, "XXX",
"YYY");
IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnection);
return databaseConnection;
}
private IDataSet getDataSet() throws Exception
{
ClassLoader classLoader = this.getClass().getClassLoader();
return new FlatXmlDataSetBuilder().build(classLoader.getResourceAsStream("database-test-setup.xml"));
}
The database-test-setup.xml file contains the data that will be inserted into the database for every test. The use of DatabaseOperation.CLEAN_INSERT in the setup method ensures that all the tables specified in the file will be cleared (by a delete of all rows) followed by an insert of the specified data in the test data file.
Avoiding DbUnit
I use the above approach specifically to clear out sequences before the start of every test, as the application uses a JPA provider which updates the sequences in a separate transaction. If your application is not doing anything like that, then you can afford to simply start a transaction in your setup() method and issue a rollback on teardown after the test. If my application didn't use sequences (and if I didn't desire to reset them), then my setup routine would have been as simple as:
#Before
public void setUp() throws Exception
{
logger.info("Performing the setup of test {}", testName.getMethodName());
// emf is created in the #BeforeClass annotated method
em = emf.createEntityManager();
// Starts the transaction before every test
em.getTransaction.begin();
}
#After
public void tearDown() throws Exception
{
logger.info("Performing the teardown of test {}", testName.getMethodName());
if (em != null)
{
// Rolls back the transaction after every test
em.getTransaction().rollback();
em.close();
}
}
Also, I use dbdeploy with Maven, but that is primarily for keeping the test database up to date with the versioned data model.
Spring's test framework does exactly that for you.
I'd handled it following ways.
When the project is in test mode. I'd used bootstraping data to to test using dbdeploy
Fixed data that you can assert on. and use the dao directly to test the DAO and DB layer of your application.
Hope it helps
Update
for example there is an entity called Person in your system, now what you can test on this is basic CRUD operations.
Run bootstraping data scripts to laod the data
retrieve all the persons from DB and assert on it. like wise see all the CRUD
to rollback the transaction you can mark
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
so it will rollback the DB stuff