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.
Related
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();
}
I have a test class to test some functions of JPA repositories, my JPA repositories are connected with H2 db, i want to populate my db with my test entites but i need to do it only once before all tests, this is my test class:
public class EntityRepositoryTest {
#Autowired
EntityJPARepository EntityRepo;
Entity entity;
#Before
public void setup(){
entiti = //initializes entity with values
EntityRepo.save(entiti);
}
//some tests on repo
}
the problem is that #Before annotiation calls it before every test method, and i dont want my entity object to duplicate in H2 db (since save will be called before every method), i also cant do in with annotation #BeforeClass since i need to call save method on #autowired repository. How can i call Setup only once before all tests but stil after repository gets autowired?
You can use the #Before method, you just need a bit of checking to do:
public class EntityRepositoryTest {
#Autowired
EntityJPARepository EntityRepo;
Entity entity;
#Before
public void setup() {
if (entity == null) { // true only for first pass
entity = //initializes entity with values
EntityRepo.save(entity);
}
}
//some tests on repo
}
Alternatively, you can add an #After method that deletes the entity.
you could use the annotation
private static boolean initialized = false;
#BeforeClass
public static void init() {
initialized = true;
}
works the same, just for static initialisations. you should define every initialisation in there. why is that not possibe for you?
you could save in a static flag wether the method has been executed or not.
There is a problem with the #BeforeClass. It is done on a static method because it is run before the instantiation of the test class. That basically means that all #Autowired parameters are not yet set. #BeforeTests method would be appreciated in the cases where you need #Autowired fields to be set but only want to run the method once. But a flag EG instantiated will fix this problem. It is however not very pretty...
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.
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.
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.