【发布时间】:2020-11-21 00:37:42
【问题描述】:
我们正在使用 Spring 5.2.x(带有 Spring Boot 2.3.x)和 Mockito 3.3.x。
我需要在我的服务中调用@Transactional 方法。因此我不得不求助于自我注射。
@Service
@RequiredArgsCostructor // lombok
public class MyClass {
private final dep1;
private final dep2;
@Autowired
private MyClass self;
public void someMethod() {
self.someTransactionalMethod();
// do something
}
@Transactional
public void someTransactionalMethod() {
// do something
}
}
public class MyClassTest {
@Mock
private dep1;
@Mock
private dep2;
@InjectMocks
private MyClass myClass;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void someMethodTest() {
// NPE when calling self.someTransactionalMethod()
}
}
从代码中可以看出,我们正在使用 lombok 进行构造函数注入。由于显而易见的原因,我不能将实例变量self 声明为final,因此为此使用@Autowired。该类工作正常,但我发现单元测试存在问题。
我的问题分为两部分 -
- 关于我进行自我注射的方式 - 这是进行自我注射的最佳方式吗?在 Spring 的最新版本中,Spring 框架的作者是否推荐了其他方法?
- Mockito 无法将自身 bean 注入 CUT(被测类)的对象中。有没有办法以干净的方式实现这一目标?
我已经考虑过以下几点:
- 为
self引入一个setter,并用它在setup 方法中注入self。不想只为测试添加 setter。 - 使用
ReflectionUtils设置self。反射对我来说似乎不干净。我更喜欢@Setter。 - 尝试使用
@RunWith(SpringJunit4Runner.class),但由于我没有创建适当的上下文和内容,因此失败了。
【问题讨论】:
-
这可能是将服务和 someTransactionalMethod() 重构为不同的类以便对其进行模拟的好案例吗?
-
someTransactionalMethod在此服务中得到了很好的定义。仅用于测试,不要认为重构是个好主意。
标签: java spring spring-boot junit mockito