如何使用 Spock 测试 Grails 服务?

Posted

技术标签:

【中文标题】如何使用 Spock 测试 Grails 服务?【英文标题】:How to test Grails service using Spock? 【发布时间】:2013-09-09 18:36:11 【问题描述】:

我有一个EncouragementService.groovy,方法如下

  class EncouragementService 
   def stripePaymentService 

   def encourageUsers(List<User> users)
     if(null != users && users.size()>0)
      for(User user : users)
        //logic
        stripePaymentService.encourage(user)
        //
      
        
   
  

要在 JAVA 世界中测试上面的代码,我会首先使用 JUnit 在 setup 中创建两个或三个用户。将用户列表传递给encourageUsers(...) 方法并检查我想要的结果。

如何在 grails 中实现同样的目标,

import com.github.jmkgreen.morphia.Datastore;

@TestFor(EncouragementService)
class EncouragementServiceSpec 

  def morphiaService = new MorphiaService()

  void testEncourageUsers() 
        List<User> users = createUsers();
        encouragementService.(users)  
            //
  

  def createUsers()
       Datastore datastore = morphiaService.dataStoreInstance()
       def user = new User()
       user.setName("Prayag Upd")
       //
       datastore.save(user)
       [user]
  

我正在使用spock:0.7

plugins 
    test(":spock:0.7")  exclude "spock-grails-support" 

【问题讨论】:

【参考方案1】:

服务类可以优化如下:

class EncouragementService 
   def encourageUsers(List<User> users)
       if(users) //Groovy truth takes care of all the checks
          for(user in users)
            //logic
          
          
   

Spock 单元测试: Spock 将测试提升到另一个层次,您可以在其中测试行为(遵守 BDD)。测试类看起来像:

import spock.lang.*

@TestFor(EncouragementService)
@Mock(User) //If you are accessing User domain object.
class EncouragementServiceSpec extends Specification
  //def encouragementService //DO NOT NEED: mocked in @TestFor annotation

  void "test Encourage Users are properly handled"() 
      given: "List of Users"
          List<User> users = createUsers()

      when: "service is called"
          //"service" represents the grails service you are testing for
          service.encourageUsers(users) 

      then: "Expect something to happen"
          //Assertion goes here
  

  private def createUsers()
       return users //List<User>
  

【讨论】:

“耐心”是my name,我不是在开玩笑;)。坦率地说,最近我在本地 Grails 用户组的 spock 上有一个 presentation,所以我想我会吹嘘我所做的一些事情。 ;) @SérgioMichels @dmahapatro 当User 不是基于grails-app/domain 的实体时,我得到Failure: test Users are properly handled(np.zazzercode.service.EncouragementServiceSpec) | org.codehaus.groovy.grails.exceptions.GrailsConfigurationException: Cannot add Domain class [class np.zazzercode.domain.User]. It is not a Domain! at grails.test.mixin.domain.DomainClassUnitTestMixin.registerGrailsDomainClass(DomainClassUnitTestMixin.groovy:209) @PrayagUpd 是的,如果 User 不是域类,那么您将不需要 @Mock 这就是我在答案中的意思。 @dmahapatro 好的,但是我如何初始化在EncouragementService 中使用的服务(例如stripePaymentService)。由于没有注入,因此在测试应用程序时抛出 java.lang.NullPointerException: Cannot invoke method encourage() on null object @dmahapatro 好吧,将def stripePaymentService = Mock(StripePaymentService) service.stripePaymentService = stripePaymentService 添加到given 已修复【参考方案2】:

使用build-test-data plugin 建立用户。

@TestFor(EncouragementService)
@Build(User)
class EncouragementServiceSpec extends Specification 

  def "encourage users does x"() 
    given:
    def users = createUsers();

    when:
    service.encourageUsers(users)  

    then:
    // assert something
  

  def createUsers()
    [User.build(), User.build(), User.build()]
  

我还对代码进行了一些更改,以使其成为正确的 spock 规范。您的测试必须扩展规范,您可能想熟悉Spock's keywords。

【讨论】:

build-test-data plugin 看起来很棒,但似乎不适用于非基于grails-app/domain 的实体。抛出异常org.codehaus.groovy.grails.exceptions.GrailsConfigurationException: Cannot add Domain class [class np.zazzercode.domain.User]. It is not a Domain

以上是关于如何使用 Spock 测试 Grails 服务?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spock 控制器测试中模拟 Grails 请求对象方法

Grails Spock单元测试需要模拟事务管理器

使用 Spock 进行 Grails 测试 - 选择哪个模拟框架?

IntelliJ IDEA 的零覆盖:带有 Spock 单元测试的 Grails

Grails / Spock:如何在类中模拟从类本身调用方法的单个方法?

在 Intellij Idea 中运行 grails 2.1.3 测试:Spock 测试中出现奇怪错误:无法添加域类 [class x.y.Z]。它不是域