【问题标题】:Spock How to mock Autowired class' function call within a methodSpock 如何在方法中模拟 Autowired 类的函数调用
【发布时间】:2016-12-17 03:05:32
【问题描述】:

我有一个要测试的类,如下所示: 包 com.something;

import org.springframework.beans.factory.annotation.Autowired;
public class ClassToTest implements InterfaceToTest{

  @Autowired
  AnotherService serviceA;

  @Override
  public List<String> methodToTest(List<String> randomVar){
    ...
    String stringA = serviceA.someFunction(randomVar);
    ...
  }
}

如何模拟调用 serviceA.someFunction(randomVar) 的结果以在使用 spock 进行测试时返回我选择的任何字符串?

package com.something;
import spock.lang.Shared
import spock.lang.Specification
class TestClass extends Specification{
  @Shared InterfaceToTest classToTest = new ClassToTest()

  static doWithSpring = {
    serviceA(AnotherService)
  }

  def "tests-part-1"(){
    when: "something"
    ...
    then: "expect this"
    ...
  }
}

我不知道从这里去哪里。我的 IDE 显示我添加到测试类的 doWithSpring 代码错误。关于如何处理这个问题的任何想法?

【问题讨论】:

    标签: spring unit-testing groovy autowired spock


    【解决方案1】:

    启用单元测试的简单解决方案是将 ClassToTest 更改为具有一个构造函数,该构造函数设置 serviceA 字段,如下所示:

    import org.springframework.beans.factory.annotation.Autowired;
    public class ClassToTest implements InterfaceToTest{
    
    private AnotherService serviceA;
    
    @Autowired
    public ClassToTest(final AnotherService serviceA){
       this.serviceA = serviceA;
    }
    
    @Override
    public List<String> methodToTest(List<String> randomVar){
    ...
    String stringA = serviceA.someFunction(randomVar);
    ...
    }
    }
    

    然后在您的 spock 单元测试中,您可以在构造函数中提供一个模拟:

    class TestClass extends Specification{
     def mockServiceA = Mock(AnotherService)
     @Shared InterfaceToTest classToTest = new ClassToTest(mockServiceA)
    

    并且在每个测试用例中,您都可以用通常的 spock 方式进行模拟:

    1 * mockServiceA.someFunction(_) >> 'A string'
    

    【讨论】:

      【解决方案2】:

      如果你是单元测试,那么按照@rockympls 的建议去做。

      如果您正在进行集成/组件测试,请包含 spock-spring 依赖项并查看 Spock 人员的 test examples。此外,如果您使用的是 Spring Boot 1.4+,您可以执行以下操作:

      @SpringBootTest(classes = Application)
      @ContextConfiguration
      class SomeIntegrationTest extends Specification {
      
          @Autowired
          SomeService someService
      
          def 'some test case'() {
              ...
          }
      }
      

      有关 Spring Boot 测试的更多信息,请参阅 this

      【讨论】:

        【解决方案3】:

        我建议从更多单元测试的角度来考虑它。您想模拟 spring 框架的东西,并确保您正在测试您的逻辑。使用 Spock 很容易做到这一点。

        ClassToTest myClass = new ClassToTest(serviceA: Mock(AnotherService))
        
        def "test my method"() {
          when:
          myClass.methodToTest([])
        
          then:
          1 * myClass.serviceA.someFunction([]) >> 'A string'
        }
        

        从这里,您可以查看驱动它的数据或使用 >>> 并传递您想要返回的不同字符串的列表。

        【讨论】:

        • 我试过这样做,但 groovy 返回 groovy.land.MissingPropertyException "No such property: serviceA for class com.something.ClassToTest
        • 这种在声明“要测试的类”时注入模拟字段的方法解决了我遇到的一个问题。我还没有在很多其他示例中看到这种方法,它真的很有用。
        猜你喜欢
        • 1970-01-01
        • 2020-12-27
        • 2019-08-29
        • 2015-02-11
        • 2016-03-04
        • 2020-05-23
        • 2017-12-29
        • 2021-12-23
        • 2018-01-09
        相关资源
        最近更新 更多