如何测试带有Spring @Transactional注解的Temporal Activity方法?
嘿,我来帮你分析下这个问题~你遇到的情况是通过Temporal的TestActivityEnvironment测试Activity方法时,@Transactional注解没正常工作,导致repo操作后的代码没执行对吧?
问题根源
你现在的测试代码里,直接把FooImpl实例注册到了测试环境,但Temporal的Activity Stub调用是直接通过反射执行方法的,绕过了Spring的事务代理机制——也就是说@Transactional注解根本没被Spring的切面处理。这就导致你的repo操作可能因为缺少事务支持抛出异常(只是没被你捕获到),所以方法执行到repo.someJpaOperation()就终止了,自然看不到There的输出。
解决方案
这里有两种更优雅的方式,不用写捕获IllegalStateException的 workaround:
方案1:注入Spring代理的Activity接口实例
因为你的FooImpl加了@Component和@Transactional,Spring会为Foo接口生成代理对象来管理事务。你只需要注入接口类型而不是实现类,再把这个代理对象注册到测试环境即可:
@DataJpaTest class MyTest { @Autowired private Foo foo; // 注入接口,拿到Spring的事务代理对象 private TestActivityEnvironment testActivityEnvironment; @BeforeEach void setUpTestActivity() { testActivityEnvironment = TestActivityEnvironment.newInstance(); testActivityEnvironment.registerActivitiesImplementations(foo); } @Test void testFoo() { val act = testActivityEnvironment.newActivityStub(Foo.class); assertThat(act.bar()).isPositive(); } }
这样Temporal调用的是Spring代理后的Foo实例,@Transactional注解会正常生效,repo操作能在事务里执行,方法也能走到最后打印There。
方案2:直接在Activity上下文里调用方法
如果不想用Stub,也可以用TestActivityEnvironment的runInActivityContext方法,直接在Temporal的上下文环境中调用Activity实现类的方法,同时保留Spring的事务支持:
@DataJpaTest class MyTest { @Autowired private FooImpl fooImpl; private TestActivityEnvironment testActivityEnvironment; @BeforeEach void setUpTestActivity() { testActivityEnvironment = TestActivityEnvironment.newInstance(); } @Test void testFoo() { // 在Activity上下文内直接调用方法,同时触发Spring事务 long result = testActivityEnvironment.runInActivityContext(() -> fooImpl.bar()); assertThat(result).isPositive(); } }
这种方式既不需要创建Stub,又能保证Activity.getExecutionContext()能正常获取到上下文,还能让Spring的事务切面正常工作,完美替代你现在的workaround。
备注:内容来源于stack exchange,提问作者Archimedes Trajano

