【问题标题】:Spock - mocking external serviceSpock - 模拟外部服务
【发布时间】:2016-03-29 09:11:50
【问题描述】:

我是 spock 框架测试的新手,我没有找到任何可以找到所需信息的示例。因此,我认为最好的方法是展示我需要具备的示例。

  1. 例如spock 中的测试类:

    def "getData" (){ // this is test of getData method from ExternalService
      when:
        Result result = externalService.getData()
      then:
        result.msg = 'SUCCESS'
    }
    
  2. 服务类:

    public class ExternalService(){
      private ServiceConnector serviceConnector;
    
      public Result getData(){
        Result result = serviceConnector.callAndGet(); 
        prepareInformation(data);
        updateStatuses(data);
        return result;
      }
    }
    
  3. 将数据分类为域类:

    public class Data {
      private String msg
      private int Id
      // +getters/setters
    }
    

现在我有getData 测试并且想模拟唯一的方法callAndGet()。这意味着每次我调用callAndGet 时,我都需要使用带有msg SUCCESS 的对象数据,但是应该正常调用getData 方法中的所有其他方法。

这很容易理解吗?问题是我们如何将服务类ExternalService 注入/模拟到 spock 测试类中?

【问题讨论】:

    标签: groovy mocking spock grails-services grails-test


    【解决方案1】:

    您不应尝试模拟服务的“仅一种方法”。这只是糟糕设计的标志,您的代码不可测试。您应该更好地使用小型服务隔离类的依赖关系,并在单元测试中模拟这些服务。然后用集成测试和你的依赖的完整实现来测试上层。

    在您的示例中,ServiceConnector 应该是一个可以轻松模拟的接口。有了这个条件,测试可以写成:

    def "test a mocked service connector"() {
      given: "a service connector"
        def serviceConnector = Mock(ServiceConnector)
    
     and: "an external service"
       def externalService = new ExternalService(serviceConnector:serviceConnector)
    
     when: "Data is loaded"
       def result = externalService.data
    
     then: "ServiceConnector is called"
       serviceConnector.callAndGet() >> new Result(msg:"SUCCESS")
    
     and: "Data is mocked"
       result.msg == "SUCCESS"
    }
    

    但是,如果 ServiceConnector 是一个类并且您无法更改它,则可以在 Spock 中使用 Partial Mock。这种测试很难维护,并且会产生很多副作用:

    def "test a mocked service connector"() {
      given: "a service connector"
        def serviceConnector = Spy(ServiceConnector) {
          callAndGet() >> new Result(msg:"SUCCESS")
        }
    
     and: "an external service"
       def externalService = new ExternalService(serviceConnector:serviceConnector)
    
     when: "Data is loaded"
       def result = externalService.data
    
     then: "Data is mocked"
       result.msg == "SUCCESS"
    }
    

    【讨论】:

      【解决方案2】:

      您需要做的是模拟 ServiceConnector 类并通过构造函数(例如)传递它。见下文:

      @Grab('org.spockframework:spock-core:1.0-groovy-2.4')
      @Grab('cglib:cglib-nodep:3.1')
      
      
      import spock.lang.*
      
      class Test extends Specification {
          def 'some spec'() {
              given:    
                  def serviceConnector = Mock(ServiceConnector) {
                      callAndGet() >> new Result(msg: 'SUCCESS')
                  }
                  def externalService = new ExternalService(serviceConnector)
      
              when:
                  Result result = externalService.getData()
      
              then:
                  result.msg == 'SUCCESS'
          }
      }
      
      public class ExternalService {
        private ServiceConnector serviceConnector
      
        public ExternalService(ServiceConnector serviceConnector) {
            this.serviceConnector = serviceConnector
        }
      
        public Result getData() {
          Result result = serviceConnector.callAndGet()
      
          prepareInformation(result)
          updateStatuses(result)
          result
        }
      
        private void prepareInformation(Result data) {
        }
      
        private void updateStatuses(Result data) {
        }
      }
      
      public class ServiceConnector {
          public Result callAndGet() {
      
          }    
      }
      
      public class Result {
          String msg
      }
      

      【讨论】:

        猜你喜欢
        • 2021-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-23
        • 2016-04-15
        • 2019-09-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多