Transactions not working in junit?

Here are a few questions about transactions and JUnit. But please read this before discarding it, as I cannot find anyone with the same problems.

I have a buisness method annotated by @Transactional . As part of this method, I will perform a software rollback if some special condition occurs. TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Now let's not discuss whether software rollbacks are good or bad. Let's just take it there and take it to stay there and work with it.

If I run my application and test this buisness method in the old fashioned way, then everything works fine. When the material needs to be rolled back, it rolls back, and when everything is in order, then everything is in order. And I also ran a test without @Transactional to make sure nothing rolls back, even if necessary. Everything works as planned.

But the problems I'm having are related to JUnit. I currently have 2 JUnit tests of this method. 1, which should fail (and cause a software rollback), and one that will succeed without a rollback.

I tried many different settings of my Junit class. Currently it looks like this:

 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:springTestContext.xml", "classpath:springTestContext-dao.xml"}) @TransactionConfiguration(transactionManager = "txManager") public class MyManagerTest extends AbstractTransactionalJUnit4SpringContextTests { @Mock private ProductDao productDao; @InjectMocks MyManager myManager = new MyManagerImpl(); @Before public void setup() { MockitoAnnotations.initMocks(this); } @Test public void testUnParsableXml() { String xml = "adlsfas"; Response response = myManager.processXMLContent(xml); assertFalse(response.isSuccess()); System.out.println(response.getResponse()); } } @Service("myManager") public class MyManagerImpl extends BaseManager implements MyManager { @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) public Response processXMLContent(String xml) { /* NB. Extremly simplified version.... */ Response response = new Response(); try { parseXml(); // just dummy sample. Its actually parsing xml response.setSuccess(true) catch(SAXException e) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); response.setSuccess(false); } return response; } } 

SpringTestContext has an annotation <tx:annotation-driven , and dao-context has an operatormanager, entityfactory, and data source. Probably not even need these? Since this test has absolutely nothing to do with db. All I want to check is that a transaction rolls back if it fails.

But the reason why I added them was because of the error with which I am trying to get help here. Whenever a program rollback is called in the buisness method, I always get this error (only for junit tests, it works fine otherwise):

 org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope 

So, my question to you is: what am I doing wrong. How can I get my buisness method for a transaction? And then as a bonus question, how can I verify that a transaction rollback was triggered?

Thanks for your time and help!

+4
source share
2 answers

You create a new instance of the MyManager class MyManager MyManager myManager = new MyManagerImpl(); instead of using the actual bean from context

 @Resource(name="myContext") MyManager myManager; 

Obviously, a proxy is not created , and the MyManager instance you are talking about is not even a Spring bean, because it is not created inside the DI container.

Regarding @Transactional annotated methods in test classes, I believe that they are executed with a TransactionalTestExecutionListener (so the mechanism is a bit smaller than in the container), but I think that this should not affect the transaction wrappers in the container itself - see beforeTestMethod and afterTestMethod. to check what has been done with the PlatformTransactionManager, if necessary.

From the documentation :

Within the TestContext, transactions are controlled by the TransactionalTestExecutionListener, which is configured through @TestExecutionListeners by default, even if you do not explicitly declare @TestExecutionListeners in your test class. to allow transaction support, however you must provide the PlatformTransactionManager bean in the context of the application loaded by @ContextConfiguration Semantics. In addition, you must declare @Transactional either at the class level or at the method level.

Therefore, I think that there are not many differences between the @Transactional launched annotated test clan methods and the actual beans (with the exception of the default rollback flag on test classes) - both the TransactionAspectSupport and the TransactionalTestExecutionListener just call the methods of the underlying PlatformTransactionManager .

PS, as for your integration test, it is not clear that you are trying to make fun of beans (both ProductDao and MyManager) - when we test integration with Spring, we check how real beans interact, making fun of only container-dependent ones (for example, using MockServletContext instead of binding to a real web server) or replacing dependencies on servers with heavy weight / production level with light / built-in - this is a balance between realistic conditions, convenience and speed of test execution.

+2
source

You need to run the test using SpringJUnit4ClassRunner , which is set by AbstractTransactionalJUnit4SpringContextTests , however you redefined it using MockitoJunitRunner . Just remove RunWith at the top of the test and it should work.

+2
source

Source: https://habr.com/ru/post/1447881/


All Articles