【问题标题】:Testing Mock Bean in Spring with Spock使用 Spock 在 Spring 中测试 Mock Bean
【发布时间】:2014-05-15 12:24:30
【问题描述】:

我遇到了 spock 不允许在规范之外创建 Mocks 的问题 - How to create Spock mocks outside of a specification class?

这似乎仍然很出色,所以我要问的是,如果我有一个复杂且嵌套的 DI 图,那么在图中“注入”模拟表示的最有效方法是什么?

理想情况下,我为正常部署设置了一个 bean 定义,在运行单元测试时设置了另一个,这个定义集是适用的 Mocks

例如

@Configuration
@Profile("deployment")
public class MyBeansForDeployment {

   @Bean
   public MyInterface myBean() {
       return new MyConcreateImplmentation();
   } 

}

&&

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

   @Bean
   public MyInterface myBean() {
       return new MyMockImplementation();
   } 

}

【问题讨论】:

    标签: spring spock


    【解决方案1】:

    从 Spock 1.1 开始,您可以在规范类之外创建模拟(分离模拟)。选项之一是DetachedMockFactory。看看the documentationmy answer to the question you linked

    【讨论】:

      【解决方案2】:

      您可以尝试实现一个 BeanPostProcessor,它将用测试替身替换您想要的 bean,如下所示:

      public class TestDoubleInjector implements BeanPostProcessor {
      ...
      
      private static Map<String, Object[]> testDoubleBeanReplacements = new HashMap<>();
      
      public void replaceBeanWithTestDouble(String beanName, Object testDouble, Class testDoubleType) {
          testDoubleBeanReplacements.put(beanName, new Object[]{testDouble, testDoubleType});
      }
      
      @Override
      public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          if (testDoubleBeanReplacements.containsKey(beanName)) {
              return testDoubleBeanReplacements.get(beanName)[TEST_DOUBLE_OBJ];
          }
      
          return bean;
      }
      

      在您的测试中,在初始化应用程序上下文之前,如下所示设置您的模拟。确保将 TestDoubleInjector 作为 bean 包含在测试上下文中。

      TestDoubleInjector testDoubleInjector = new TestDoubleInjector()
      testDoubleInjector.replaceBeanWithTestDouble('beanToReplace', mock(MyBean.class), MyBean.class)
      

      【讨论】:

        【解决方案3】:

        可以使用HotSwappableTargetSource来完成

        @WebAppConfiguration
        @SpringApplicationConfiguration(TestApp)
        @IntegrationTest('server.port:0')
        
        class HelloSpec extends Specification {
        
        @Autowired
        @Qualifier('swappableHelloService')
        HotSwappableTargetSource swappableHelloService
        
        def "test mocked"() {
          given: 'hello service is mocked'
          def mockedHelloService = Mock(HelloService)
          and:
          swappableHelloService.swap(mockedHelloService)
        
          when:
          //hit endpoint
          then:
          //asserts 
          and: 'check interactions'
          interaction {
              1 * mockedHelloService.hello(postfix) >> { ""Mocked, $postfix"" as String }
          }
          where:
          postfix | _
          randomAlphabetic(10) | _
        }
        }
        

        这是TestApp(用代理覆盖你想模拟的bean)

        class TestApp extends App {
        
        //override hello service bean
        @Bean(name = HelloService.HELLO_SERVICE_BEAN_NAME)
        public ProxyFactoryBean helloService(@Qualifier("swappableHelloService") HotSwappableTargetSource targetSource) {
        def proxyFactoryBean = new ProxyFactoryBean()
        proxyFactoryBean.setTargetSource(targetSource)
        proxyFactoryBean
        }
        
        @Bean
        public HotSwappableTargetSource swappableHelloService() {
          new HotSwappableTargetSource(new HelloService());
        }
        }
        

        看看这个例子https://github.com/sf-git/spock-spring

        【讨论】:

          猜你喜欢
          • 2012-04-06
          • 2018-04-29
          • 1970-01-01
          • 1970-01-01
          • 2022-11-24
          • 1970-01-01
          • 1970-01-01
          • 2019-07-18
          • 2023-03-31
          相关资源
          最近更新 更多