title: Spring - Testing method that use TransactionSynchronizationManager
body: <p>I use in my service <code>TransactionSynchronizationManager.registerSynchronization(...)</code> and I cannot write test for this method, because I get an exception: <code>java.lang.IllegalStateException: Transaction synchronization is not active</code>. </p>
  
  <p>Implementation of my service:</p>
  
  <pre><code>@Transactional
  public void save(Order order) {
      log.info("Starting transaction...");
      orderDAO.save(order);
      TransactionSynchronizationManager.registerSynchronization(
              new TransactionSynchronizationAdapter() {
                  @Override
                  public void afterCommit() {
                      log.info("#afterCommit");
                      eventPublisher.publishEvent(new OrderPlacedEvent(order));
                  }
              }
      );
      log.info("Commit");
  }
  </code></pre>
  
  <p>And test which doesn't work:</p>
  
  <pre><code>@RunWith(SpringRunner.class)
  public class OrderServiceTest {
  
      private OrderDAO orderDAO;
      private ApplicationEventPublisher eventPublisher;
      private OrderService orderService;
  
      @Before
      public void setUp() throws Exception {
          orderDAO = mock(OrderDAO.class);
          eventPublisher = mock(ApplicationEventPublisher.class);
          orderService = new OrderService(
                  orderDAO,
                  eventPublisher
          );
      }
  
      @Test
      public void save() throws Exception {
          // given
          final Order order = new Order(1L, "ORDER");
  
          // when
          orderService.save(order);
  
          // then
          verify(orderDAO).save(any(Order.class));
          verify(eventPublisher).publishEvent(any(OrderPlacedEvent.class));
      }
  
  }
  </code></pre>
  
  <p>And stacktrace:</p>
  
  <pre><code>java.lang.IllegalStateException: Transaction synchronization is not active
  
      at org.springframework.transaction.support.TransactionSynchronizationManager.registerSynchronization(TransactionSynchronizationManager.java:291)
      at com.events.eventsdemo.services.OrderService.save(OrderService.java:32)
      at com.events.eventsdemo.services.OrderServiceTest.save(OrderServiceTest.java:52)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
      at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
      at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
      at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
      at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
      at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
      at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
      at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
      at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
      at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
  </code></pre>
  
  <p>UPDATE:</p>
  
  <p>Implementation of my main class:</p>
  
  <pre><code>@SpringBootApplication
  @EnableTransactionManagement
  public class TransactionsDemoApplication {
  
      public static void main(String[] args) {
          SpringApplication.run(TransactionsDemoApplication.class, args);
      }
  }
  </code></pre>
  
  <p>Service:</p>
  
  <pre><code>@Slf4j
  @Service
  public class OrderService {
  
      private final OrderDAO orderDAO;
      private final ApplicationEventPublisher eventPublisher;
  
      @Autowired
      public OrderService(OrderDAO orderDAO, ApplicationEventPublisher eventPublisher) {
          this.orderDAO = orderDAO;
          this.eventPublisher = eventPublisher;
      }
  
      @Transactional
      public void save(Order order) {
          log.info("Starting transaction...");
          orderDAO.save(order);
          TransactionSynchronizationManager.registerSynchronization(
                  new TransactionSynchronizationAdapter() {
                      @Override
                      public void afterCommit() {
                          log.info("#afterCommit");
                          eventPublisher.publishEvent(new OrderPlacedEvent(order));
                      }
                  }
          );
          log.info("Commit");
      }
  }
  </code></pre>
  
  <p>and test for Service:</p>
  
  <pre><code>@RunWith(SpringRunner.class)
  @SpringBootTest
  public class OrderServiceTest {
  
      @MockBean
      private OrderDAO orderDAO;
  
      @MockBean
      private ApplicationEventPublisher eventPublisher;
  
      @Autowired
      private OrderService orderService;
  
      @Test
      public void save() throws Exception {
          // given
          final Order order = new Order(1L, "ORDER");
  
          // when
          orderService.save(order);
  
          // then
          verify(orderDAO).save(any(Order.class));
          verify(eventPublisher).publishEvent(any(OrderPlacedEvent.class));
      }
  
  }
  </code></pre>
  
  <p>but I get an exception:</p>
  
  <pre><code>Wanted but not invoked:
  org.springframework.context.ApplicationEventPublisher#0 bean.publishEvent(
      &lt;any&gt;
  );
  -&gt; at com.transactions.demo.transactionsdemo.dao.OrderServiceTest.save(OrderServiceTest.java:39)
  Actually, there were zero interactions with this mock.
  
  Wanted but not invoked:
  org.springframework.context.ApplicationEventPublisher#0 bean.publishEvent(
      &lt;any&gt;
  );
  -&gt; at com.transactions.demo.transactionsdemo.dao.OrderServiceTest.save(OrderServiceTest.java:39)
  Actually, there were zero interactions with this mock.
  
      at com.transactions.demo.transactionsdemo.dao.OrderServiceTest.save(OrderServiceTest.java:39)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:498)
      at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
      at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
      at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
      at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
      at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
      at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
      at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
      at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
      at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
      at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
      at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
      at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
      at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
      at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
      at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
      at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
      at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
      at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
      at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
      at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
      at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
      at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
  </code></pre>
  
  <p>Maybe I should mock <code>TransactionSynchronizationAdapter</code>? But I don't know how to inject mocked implementation of this adapter. Any idea?</p>
  
  <p>OrderServiceTest:39 is line: <code>verify(eventPublisher).publishEvent(any(OrderPlacedEvent.class));</code></p>