在Service bean内部模拟Service bean中的方法(Spring Boot 2.5)



我读了很多关于春天内心嘲笑的问题和答案,但我不能把我的场景付诸实践…

我需要对一个Spring服务bean (a)进行单元测试,该bean (a)@Autowire另一个服务bean (B),并在其中执行一个方法B.method()。这个方法在bean (A)的@PostConstruct方法中执行。我使用Spring Boot 2.5 (JUnit 5)。

@Autowirebean (A)在我的测试类,但我找不到一种方法来模拟B.method(),所以当我运行@Autowire(A),它自动连接(B),当A执行B.method(),该方法被模拟。

我试过@Spy,@SpyBean,@MockBean,…

class TestClass {
@Autowired
private A a;
@Test
mytest () {
a.anyMethod();
}
}
@Service
class A {
@Autowired B b;
@Postconstruct
public void postconstruct() {
b.methodToBeMocked();
}
}
@Service
class B {
public void methodTobeMocked(){
}
}

是棘手的可能指出,应用程序的设计可能得到改善。

@MockBean替换测试执行的现有bean。前面调用了@PostConstruct

您可以使用@TestConfiguration向您的上下文中提供已经模拟和启动的bean。

我添加了一个简单的、可执行的例子:

package de.trion.training;
@SpringBootTest(classes = {MockingSample.class, MockingSample.B.class,
MockingSample.A.class, MockingSample.MockInit.class})
public class MockingSample
{
@Autowired
private A a;

//too late!
//@MockBean
//private static B b;
//@BeforeEach
//void setUp()
//{
//    when(b.methodToBeMocked()).thenReturn("mocked!");
//}
@TestConfiguration
static class MockInit
{
@Primary
@Bean
B makeB()
{
var b = mock(B.class);
when(b.methodToBeMocked()).thenReturn("mocked!");
return b;
}
}

@Test
void mytest()
{
a.anyMethod();
}
@Service
public static class A
{
@Autowired
private B b;
private String result;
@PostConstruct
public void postconstruct()
{
result = b.methodToBeMocked();
System.out.println("postconstruct: " + result);
}
public void anyMethod()
{
System.out.println("anymethod: " + result);
}
}
@Service
public static class B
{
public String methodToBeMocked()
{
return "real";
}
}
}

试着让你的单元测试尽可能简单,不需要启动Spring来测试它。你正在测试A的代码,但没有测试Spring是否正确配置和初始化A。

这意味着您可以简单地通过构造函数手动将B注入A,并在测试任何A的方法之前手动调用@Postconstruct方法。

也不需要@SpringBootTest。只是一个普通的JUnit5测试5朋友,像下面应该够了。它也会使你的测试运行得更快,因为它不需要引导Spring。

@ExtendWith(MockitoExtension.class)
public class ATest {

@Mock
private B b;

private A a;

@BeforeEach
public void init(){
a = new A(b);
}

@Test
public void fooTest(){

//stub B method
when(b.methodToBeMocked()).thenReturn("xxxxxxxx");

//manually call @Postconstruct before starting testing on A
a.postconstruct();

//start your testing on A
a.someMethod();
}
}

最新更新