How to revert the database back to the initial state using dbUnit? - java

I am new to automated testing and dbUnit. So I would appreciate your advice.
I am going to create a test suite, that will run the following way:
create an in-memory H2 database
run DDL scripts to create tables
run dbUnit to insert initial data (let's call it STATE0) that will be used by all tests.
run tests
Till there it looks nice for me, but what I don't understand, is how do I revert the database to the STATE0 after a test run and changed the data?
Can I do it with dbUnit?
Or with something else?
Should I recreate the database before each test?
Simple not commiting transactions in tests is not appropriate for me, because the tests will eventually run more than one transaction over may be more than one database connection.

DBUnit can do the work four you automatically if you write your #BeforeClass, #Before and #After methods properly. E.g. in our project, using Derby, one such test case looks like
public class MyTest {
protected static IDataSet getDataSet() throws Exception {
URL url = MyTest.class.getClassLoader().getResource("MyDataSet.xml");
return new XmlDataSet(new FileInputStream(url.getPath()));
}
private static JdbcDatabaseTester databaseTester;
#BeforeClass
public static void setUpClass() throws Exception {
// Init test environment, session etc.
databaseTester = new JdbcDatabaseTester(
"org.apache.derby.jdbc.ClientDriver",
"jdbc:derby://localhost:1527/myschema",
"username", "password");
databaseTester.setDataSet(getDataSet());
}
#AfterClass
public static void tearDownClass() {
// Close session etc.
}
#Before
public void setUp() throws Exception {
databaseTester.onSetup();
}
#After
public void tearDown() throws Exception {
databaseTester.onTearDown();
}
#Test
public void test() throws Exception { ... }
}
This code puts back (a subset of) the DB schema to the state defined by MyDataSet.xml after each test. (Note that, as #Pascal commented, the reset may not always be full - if a test modifies a table which is not in the dataset, it won't be affected by the #Before / #After methods.)

To initialize the database to the initial dataset, just implement these methods in your test case :
#Override
protected DatabaseOperation getSetUpOperation() throws Exception
{
return DatabaseOperation.CLEAN_INSERT; // by default (will do DELETE_ALL + INSERT)
}
#Override
protected DatabaseOperation getTearDownOperation() throws Exception
{
return DatabaseOperation.NONE; // by default
}
You may have foreign keys constraints if some of your tests insert rows in an empty table (not defined in initial dataset for example).
Just add this empty table in your dataset without any row :
<mydb_mypopulatedtable id="1" name="toto" alias="funky"/>
<mydb_mypopulatedtable id="2" name="titi" alias="groovy"/>
<mydb_mypopulatedtable id="3" name="tutu" alias="creepy"/>
<mydb_myemptytable />
Here, myemptytable has a foreign key to mypopulatedtable. If myemptytable was not defined, DBUnit would try to delete the mypopulatedtable but will fail because of the constraint. If defined, DBUnit will delete myemptytable rows before.

Related

Unable to run Unit Test when call function in #PostConstruct

I'm woking on EJB Project, using JPA to query data. Now, I create unit test and use mockito to mock data. There is a function that I call data from criteria builder, and it's called from #PostConstruct. So if result is empty, then it will throw NoResultException. However, I am unable to run unit test to test it. Take a look on source code below:
For class RefdataUpdateDaoImpl
public class RefdataUpdateDaoImpl{
public RefdataUpdate getSingleUpdate() {
CriteriaBuilder cb = getCriteriaBuilder();
CriteriaQuery<RefdataUpdate> query = cb.createQuery(RefdataUpdate.class);
Root<RefdataUpdate> rootEntry = query.from(RefdataUpdate.class);
CriteriaQuery<RefdataUpdate> all = query.select(rootEntry);
TypedQuery<RefdataUpdate> allQuery = getEntityManager().createQuery(all);
return allQuery.getSingleResult();
}
}
In RefDataCacheBean
#PostConstruct
private void postConstruct() throws Exception{
cachedUpdateTs = RefdataUpdateDaoImpl.getLastUpdate();
}
This is unit test
#Test(expected = NoResultException.class)
public void testExistingRefDataUpdate() throws NoResultException{
update.deleteRefDataUpdate();
refdataServiceBean.getLastUpdate();
}
So in unit test, it loads data from dataset xml. So when I run test, it supposes to throw NoResultException and test passes, but test fails and console log no entity data found.
Please help to create unit test in this case, when function's called from #PostConstruct.
Trace Logs:
javax.ejb.EJBException: javax.persistence.NoResultException: No entity found for query
Thank you and any comments will be appreciated.
Obviously the NoResultException is nested in a EJBException so your test code should be:
#Test(expected = EJBException.class)
public void testExistingRefDataUpdate() throws NoResultException{
update.deleteRefDataUpdate();
refdataServiceBean.getLastUpdate();
}

How to test rollback of transaction in Hibernate+Spring+JUnit

I am trying to test the mechanism of rollbackin transaction in cases of somthing went wrong. I read many similar topics, but nothing helps me. Here is what i try:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/rest-servlet.xml" })
#Transactional
public class TagDaoImplTest extends DatabaseTestCase {
private static final String FLAT_XML_DATASET = "FlatXmlDataSet.xml";
#Autowired
private TagDao tagDao;
#Autowired
private SessionFactory sessionFactory;
#Before
public void setUp() throws Exception {
DatabaseOperation.REFRESH.execute(getConnection(), getDataSet());
}
#Test
public void testAddWithRollback() throws Exception {
addWithRollback("testTagToAdd"); //i suppouse that we tried to add, but somthing went wrong and transaction was rolled back
final Tag testTagToAdd = tagDao.findByTag("testTagToAdd"); // so db must be without changes and i check this
assertNull(testTagToAdd);
}
#Rollback(true) //i want this method to rollback after its work to imitate corrupted transaction
private void addWithRollback(String tag) throws Exception {
tagDao.add(new Tag(tag));
}
}
My dao looks like this:
#Repository("tagDao")
public class TagDaoImpl implements TagDao {
#Override
public void add(Tag tag) {
final Session session = sessionFactory.getCurrentSession();
session.persist(tag);
}
}
But my test fails because it finds that tag in db (and this means transaction wasn`t rolled back). I tried many different things like get current session and transaction and manually invoke rollback, but nothing happend. Can you please help me?
First of all, for me it feels a bit weird that you try to test the repository layer. Normally there should not be any business logic, thus this means that you try to test Hibernate or SQL which are already tested million of times and there is no point of doing it.
I would suggest to annotate your method with something like this:
#Transactional(rollbackFor=Exception.class)
and maybe specify the Exception. Then in the test you prepare your system in a way that this method throws this exception. Thus it should be rolled back and no data should be changed.
Furthermore, I would like to add that actually loading spring context at this point most probably is different compare to the production one. Thus this is an additional point where I would say that there is no point of doing it. At least on the repository layer.

How to clean all entities from EntityManager?

I'm working on a JavaEE application with EJB and JPA.
I'm doing some tests and entities are persisting. Although, I'd like to remove entities between those tests. I tried to use the method EntityManager.clear() but this doesn't work. When I try to consult one of the old entities, it is still on the EntityManager.
How can I solve this problem?
Invoking EntityManager.clear() will not remove the entities, because they are persisted in the database.
You could close your entity manager factory and open again:
#Before
public void beforeTest() {
entitManagerFactory.close()
entitManagerFactory = // new EntityManagerFactory
}
The problem with this approach is that create an EntityManager may slow down the tests process.
What you could do instead is:
1) You could delete all entities before the test:
#Before
public void beforeTest() {
// execute a query like delete from Person p
}
2) You could use a new ID/values for every test:
#Test
public void test1() {
Person person = PersonTestUtil.createPerson("11111");
}
#Test
public void test2() {
Person person = PersonTestUtil.createPerson("22222");
}

Spring Data Rest Unit Tests Selectively Pass

I am investigating the use of Spring Data Rest (2.0.1.RELEASE and Spring 4.0.2.RELEASE), and have written a simple service. I have also written a simple test class (see below) using DbUnit.
Unfortunately when I run the tests only the findAll method passes. If I comment out the findAll method then the findInvestigationalProductById passes and directLink fails. If I then comment out findInvestigationalProductById then directLink passes.
None of these methods changes data state, so I would like to know if there is some configuration I have overlooked that can cause this behaviour.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/com/perceptive/ctms/core/tests-context.xml"})
#WebAppConfiguration
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DbUnitTestExecutionListener.class })
#DatabaseSetup("investigational-products-data.xml")
public class InvestigationalProductTests {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
MockitoAnnotations.initMocks(this);
}
#Test
public void findAll() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct", hasSize(3)));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[0].investigationalProductCode", is("ACTIVE1")));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[1].investigationalProductCode", is("ACTIVE2")));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[2].investigationalProductCode", is("ACTIVE3")));
}
#Test
public void directLink() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct/3"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
System.out.println(resultActions);
resultActions.andExpect(jsonPath("$investigationalProductCode", is("ACTIVE3")));
}
#Test
public void findInvestigationalProductById() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct/search/findInvestigationalProductById?id=3"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct", hasSize(1)));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[0].developmentName", is("developmentName3")));
}
}
This is a misunderstanding about how #DatabaseSetup works. The problem tests are all dealing with referencing data by a generated id. The API states:
Test annotation which indicates how to put a database into a know
state before tests are run. This annotation can be placed on a class
or on methods. When placed on a class the setup is applied before each
test methods is executed.
which to my mind is a little ambiguous, but additional documentation states:
By default setup will perform a CLEAN_INSERT operation, this means
that all data from tables referenced in the DataSet XML will be
removed before inserting new rows.
i.e. tests should not assume that the database (including any sequence numbers) is put into a clean state, just that the data is clean.
Adding the following code
private static int currentOffset = 0;
private static final int TEST_OFFSET = 3;
/**
* After each test is run DatabaseSetup annotation deletes records
* and inserts fresh ones - this means we need to keep track of the
* current offset
*/
#After
public void offset() {
currentOffset += TEST_OFFSET;
}
(with occasional modifications to currentOffset when testing inserts) can keep track of the current ids.
This does not seems ideal, but I do not know a way of resetting the database to a truly clean state.

How to perform Savepoint and rollback in Hibernate?

I am making Test of My classes so I am inserting so many data for to test my code.
So I am thinking to make some mechanism of savepoint and rollback in DB.
I am using postgresql as DB sever.
Following is my code for test :
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("file:src/main/webapp/WEB-INF/ls-dispatcher-servlet.xml")
public class AddBindingProcessorTest extends IntegrationTestBase {
#Autowired
private AddBindingProcessor processor;
public AddBindingProcessorTest(){
}
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void add() throws Exception {
AddBinding command;
command = new AddBinding();
command.setId(50l);
command.setBindingName("bindingtest1");
command.setBindingPrice((double)253);
BindingTypeResponse response = (BindingTypeResponse)processRequest(command);
System.out.println("from addbindingprocessor test "+response.getBindingName());
}
}
Here I am setting value through command object and passing to ProcessRequest() Method that will store data inside DB using hibernate.
Still I have to write assert in my testProcess() method that will check data is correct or not ?
So my question is that I when this transaction starts in setUp() method one savepoint should be created and then testProcess() method will be executed and assert check for the data that they are correct or not and then in tearDown() method I want to rollback to savepoint that is set in setUp() method.
So how to do so ? If Anyone can just guide me that what I ll have use and how to move forward then I ll learn that thing and go by myself.
I just want guidance about it that what I ll have to use and where ?
Thank You All.
If I get you right, you can just use the
#TransactionConfiguration(defaultRollback = true)
annotation below your #ContextConfiguration annotation.
This will rollback the changes in your tests after every run.
user3145373 pointed out, that the attribute transactionManager="context bean transaction manager" in #TransactionConfiguration needed to be set also.
It is part of the spring-test lib.

Categories

Resources