Spring and JUnit annotated tests: creating fixtures in separate transactions
I am testing my Hibernate DAOs with Spring and JUnit.
I would like each test method to start with a pre-populated DB, i.e. t开发者_如何学编程he Java objects have been saved in the DB, in a Hibernate transaction that has already been committed. How can I do this?
With @After and @Before, methods execute in the same Hibernate transaction as the methods decorated with @Test and @Transactional (first level cache may not be flushed by the time the real test method starts). @BeforeTransaction and @AfterTransaction apparently cannot work with Hibernate because they don't create transactions even if the method is annotated with @Transactional in addition to @Before/AfterTransaction.
Any suggestion?
One way could be to externalize your intialization logic to an external service with transactional methods which are executed from your @BeforeTransaction and @AfterTransaction annotated methods in the test class.
Another benefit of this approach is the reusability of initialization code across tests.
You could for example use the SpringJunit4ClassRunner like described here like this:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"testContext.xml","services.xml"})
public class MyServiceTest {
@Autowired
private TestDataService testDataService;
@Before
public void setUp(){
testDataService.addTestData();
}
@Test
public void testSomething() throws Exception {
// ...
}
}
public interface TestDataService {
void addTestData();
}
public class TestDataServiceImpl implements TestDataService {
@Transactional
public void addTestData(){
// TODO
}
}
That's something we do in our Spring based projects.
Make sure the transactional configuration is correct. If you want to avoid the class/interface separation, then set proxy-target-class to true in the element.
dbUnit is a good framework for the job.
In short, it should be started from the setUp()
method and it deletes all contents from specified tables, then fill them up with content from a XML file.
Else you can try to execute the setUp()
method in a new transaction like this:
@Before
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void setUp() {
// initial logic ..
}
精彩评论