Spring 自注及用mockito测试

ubof19bj  于 2022-12-12  发布在  Spring
关注(0)|答案(2)|浏览(196)

我们使用的是Spring 5.2.x(带Sping 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。类工作正常,但我发现单元测试有问题。
我的问题分为两部分-
1.关于我做自我注入的方式--这是做自我注入的最好方式吗?在Spring的最新版本中,Spring框架的作者还推荐了其他的方法吗?

  1. Mockito根本无法将self bean注入到CUT(Class Under Test)的对象中,有没有一种干净的方法可以做到这一点?
    我已经考虑了以下几点:
    1.为self引入一个setter,并使用它在setup方法中注入self。不要只为测试添加setter。
    1.使用ReflectionUtils来设置self。反射对我来说似乎不干净。我更喜欢@Setter而不是这个。
    1.尝试使用@RunWith(SpringJunit4Runner.class),但如预期的那样失败了,因为我没有创建适当的上下文和东西。
cs7cruho

cs7cruho1#

在setUp()方法中调用ReflectionTestUtils.setField(myClass,“自我”,myClass)

vpfxa7rd

vpfxa7rd2#

如果插入自引用很困难或者你需要ReflectionTestUtils来完成它,这是因为测试不是一个纯单元测试,在你的情况下,这是因为服务没有一个定义好的接口。如果我们改变服务来实现一个接口,并将测试改为纯单元测试,代码将变成如下所示,问题也就消失了:

public class MyClass implements MyInterface {

    @Inject
    private MyInterface self;

    @Override
    public void someMethod() {
        self.someTransactionalMethod();
    }

    @Override
    @Transactional
    public Object someTransactionalMethod() {
        throw new UnsupportedOperationException("Not implemented yet");
    }
}

测试变成:

@RunWith(MockitoJunitRunner.class)
public class MyClassTest {

    @Mock
    private MyInterface self;

    @InjectMocks
    private MyClass service;

    @Test
    public void someMethodShouldCallSelf() {
        when(self.someTransactionalMethod()).thenReturn("test");
        service.someMethod();
        verify(self, times(1)).someTransactionalMethod();
    }
}

现在,someMethod()的测试遵循单元测试原则,实际上只测试someMethod()中的代码,而不是将someTransactionalMethod()包括在它的复杂性中。然后,您为someTransactionalMethod()编写单独的单元测试,以确保它正常运行。

相关问题