如何在@SpringBootTest 中创建可重用的@MockBean 定义?

How to create reusable @MockBean definitions in @SpringBootTest?

我有一个 @SpringBootTest class,它有一个相当复杂的模拟定义设置,带有模拟的 return 值。

问题:我可以将 @MockBean 设置外部化为自己的 class,这样我就可以在多个 class 中重复使用模拟配置(旁注:我是 不是在这里寻找继承!)。

@SpringBootTest
public class ServiceTest extends DefaultTest {
    @Autowired
    private ServiceController controller;
    
    @MockBean
    private Service1 s1;
    
    @MockBean
    private Service2 s2;
    
    @MockBean
    private Service3 s3;
    
    //assume more complex mock definitions
    @BeforeEach
    public void mock() {
        when(s1.invoke()).thenReturn(result1);
        when(s2.invoke()).thenReturn(result2);
        when(s3.invoke()).thenReturn(result3);
    }
    
    @Test
    public void test() {
        //...
    }
}

我想独立加载模拟,而不是全局加载我的所有测试。

我想你的答案就在这里:

像这样创建一个实现这些 MockBeans 的测试配置文件:

@Profile("test")
@Configuration
public class MyMockConfiguration {

    @Bean
    public SomeService someService() {
        SomeService someService = mock(SomeService .class);
        // mocked methods and results
        return someService ;
    }

然后在您的测试中使用带有这些注释的配置文件 class:

@ActiveProfiles("test")
@SpringBootTest
@WebAppConfiguration
@RunWith(SpringRunner.class)

不是您所要求的,但一种可能性是不使用 @MockBean,而是将您的可重用模拟定义为 @Primary @Bean 多个 @TestConfiguration您可以在测试中选择性地 @Import:

@TestConfiguration
public class MockService1 {

  @Bean
  @Primary
  public Service1 service1Mock() {
    Service1 s1 = Mockito.mock(Service1.class);
    when(s1.invoke()).thenReturn("result1");
    return s1;
  }
}

关于这种方法有一篇不错的文章:Building Reusable Mock Modules with Spring Boot

仅供参考(如果 @TestConfiguration 方法可能出于某种原因不适合),它在创建 junit 时也有效 Extension:

public class MockService1Extension implements BeforeTestExecutionCallback {
    @Override
    public void beforeTestExecution(ExtensionContext extensionContext) throws Exception {
        ApplicationContext springContext = SpringExtension.getApplicationContext(extensionContext);
        Service1 s1 = springContext.getBean(Service1.class);
        when(s1.invoke()).thenReturn("result1");
    }
}


@ExtendWith(MockService1Extension1.class)
@MockBean({Service1.class})
public class TestImpl {
    @Test
    public void test() {
    }
}

不幸的是,对于这种方法,实施测试必须在 class 级别上另外列出在扩展中模拟的 beans @MockBean