【问题标题】:How to create reusable @MockBean definitions in @SpringBootTest?如何在@SpringBootTest 中创建可重用的@MockBean 定义?
【发布时间】:2021-07-07 06:37:59
【问题描述】:

我有一个 @SpringBootTest 类,它有一个相当复杂的模拟定义设置和模拟返回值。

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

@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() {
        //...
    }
}

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

【问题讨论】:

    标签: java spring junit spring-boot-test


    【解决方案1】:

    仅供参考(如果@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() {
        }
    }
    

    不幸的是,对于这种方法,实现测试必须在类级别上另外列出在扩展内模拟的 bean,并加上 @MockBean

    【讨论】:

      【解决方案2】:

      不是您直接要求的,但一种可能性是不使用@MockBean,而是在多个@TestConfigurations 中将您的可重用模拟定义为@Primary@TestConfigurations,您可以在您的@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

      【讨论】:

      • 然后在我的测试中使用@Import(MockService1.class)?这确实是一个好主意,我一直为此苦苦挣扎,因为在这种情况下不可能注入@MockBean。但是Mockito.mock() 似乎有效!
      • @membersound 是的,只需@Import 任何你在测试中需要的模拟。
      • 或者,您可以使用@SpringBootTest(classes = {MockService1.class})定义配置
      【解决方案3】:

      我想你的答案就在这里: https://stackoverflow.com/a/50802303/10811865

      创建一个实现这些 MockBean 的测试配置文件,如下所示:

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

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

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

      【讨论】:

      • 好吧,但我想选择性地加载模拟的 bean!这将始终为所有使用“测试”配置文件的测试启用模拟(或者我必须创建 N 个测试配置文件 - 这也不好),因此与从抽象测试类的简单继承相比没有优势。
      • 啊,我误会了。您可能想在您的问题中添加您想要彼此独立加载模拟
      猜你喜欢
      • 2021-10-04
      • 2022-01-04
      • 2021-06-28
      • 1970-01-01
      • 2017-09-07
      • 2013-05-02
      • 1970-01-01
      • 1970-01-01
      • 2020-11-03
      相关资源
      最近更新 更多