Unit testing 在域类中测试服务

Unit testing 在域类中测试服务,unit-testing,grails,grails-2.0,Unit Testing,Grails,Grails 2.0,我现在正试图为我的一个域类编写一个单元测试。我作弊了,我知道代码是用代码工作的,但是。。。我想确保我有一些自动测试 我得到以下错误: Test a sponsor(some.vendor.Vendor2Spec) | java.lang.NullPointerException: Cannot invoke method getLevel() on null object at some.vendor.Vendor.getSponsorLevel(Vendor.groovy:1

我现在正试图为我的一个域类编写一个单元测试。我作弊了,我知道代码是用代码工作的,但是。。。我想确保我有一些自动测试

我得到以下错误:

Test a sponsor(some.vendor.Vendor2Spec)
 |
java.lang.NullPointerException: Cannot invoke method getLevel() on null object
        at some.vendor.Vendor.getSponsorLevel(Vendor.groovy:111)
        at some.vendor.Vendor2Spec.Test a sponsor(Vendor2Spec.groovy:29)
|Completed 1 unit test, 1 failed in 0m 3s
.................Tests FAILED
在下面的代码中,我指出了我的行号,这些行号被称为错误

我的
供应商
看起来像:

class Vendor {
  def sponsorService

  SponsorLevel getSponsorLevel(){
    return sponsorService.getLevel(this)  // Line 111
  }
}
class SponsorService {
  static transactional = false

  def getLevel(Vendor vendor){
    if(!vendor){
      return null
    }
    BigDecimal sponsoringAmount = BigDecimal.ZERO

    sponsoringAmount = sponsoringAmount.add(vendor.cashDonation ?: BigDecimal.ZERO)
    sponsoringAmount = sponsoringAmount.add(vendor.itemValue ?: BigDecimal.ZERO)

    return SponsorLevel.getSponsoringLevel(sponsoringAmount)
  }
}
我的测试设置如下:

@TestFor(Vendor)
@TestMixin(GrailsUnitTestMixin)
class Vendor2Spec  extends Specification{

  @Shared
  def sponsorService = new SponsorService()

  def setup() {
  }

  def cleanup() {
  }

  void "Test a sponsor"(){
    when: 'A Sponsor donates $5'
    def vendor = new Vendor(cashDonation: 5, sponsorService: sponsorService)
    then: 'Amount Owed should be $5'
    vendor.getAmountDue().equals(new BigDecimal("5"))
    vendor.getSponsorLevel() == SponsorLevel.DIAMOND  // Line 29

    when:"A Sponsor donates an item of value"
    vendor = vendor = new Vendor(itemValue: 5)
    then: 'Amount Due is $0'
    vendor.getAmountDue().equals(new BigDecimal("0"))
    vendor.sponsorLevel == SponsorLevel.DIAMOND
  }

}
当我刚开始的时候,我并没有更新我的
赞助商服务
,它一直在抱怨为空,所以。。。我试着嘲笑(可能做错了),但是。。。我需要测试服务的对象使用情况,以便。。。我想我不需要嘲笑

该服务看起来像:

class Vendor {
  def sponsorService

  SponsorLevel getSponsorLevel(){
    return sponsorService.getLevel(this)  // Line 111
  }
}
class SponsorService {
  static transactional = false

  def getLevel(Vendor vendor){
    if(!vendor){
      return null
    }
    BigDecimal sponsoringAmount = BigDecimal.ZERO

    sponsoringAmount = sponsoringAmount.add(vendor.cashDonation ?: BigDecimal.ZERO)
    sponsoringAmount = sponsoringAmount.add(vendor.itemValue ?: BigDecimal.ZERO)

    return SponsorLevel.getSponsoringLevel(sponsoringAmount)
  }
}
以及枚举:

enum SponsorLevel {
    PLATINUM("Platinum"),
  GOLD("Gold"),
  SILVER("Silver"),
  BRONZE("Bronze"),
  DIAMOND("Diamond")

  final String label

  private SponsorLevel(String label){
    this.label = label
  }

  public static SponsorLevel getSponsoringLevel(BigDecimal sponsoringAmount){
    if(!sponsoringAmount){
      return null
    }    
    if(sponsoringAmount.compareTo(new BigDecimal("3000")) >= 0){
      return PLATINUM
    }
    if(sponsoringAmount.compareTo(new BigDecimal("2000")) >= 0){
      return GOLD
    }
    if(sponsoringAmount.compareTo(new BigDecimal("1000")) >= 0){
      return SILVER
    }
    if(sponsoringAmount.compareTo(new BigDecimal("500")) >= 0){
      return BRONZE
    }
    if(sponsoringAmount.compareTo(new BigDecimal("1")) >= 0){
      return DIAMOND
    }
    return null
  }
}

一般来说,当从其他类调用服务类进行单元测试时,应该模拟服务类,否则,您可能需要编写集成测试

就个人而言,如果这就是您的服务所做的一切,我会将其作为域本身的一种方法:

class Vendor {
  def sponsorService

  SponsorLevel getSponsorLevel(){
    BigDecimal sponsoringAmount = BigDecimal.ZERO

    sponsoringAmount = sponsoringAmount.add(this.cashDonation ?: BigDecimal.ZERO)
    sponsoringAmount = sponsoringAmount.add(this.itemValue ?: BigDecimal.ZERO)

    return SponsorLevel.getSponsoringLevel(sponsoringAmount)
  }
}

您的服务不是事务性的,您的
getLevel()
对数据库没有任何作用,并且该方法特定于您的供应商域。所以对我来说,将其作为供应商的域方法更有意义。它简化了您的代码和测试。

这绝对是可能的!我会回去看看,看看其他东西是如何相互作用的。我还有其他一些事情没有包括在这里。最初,从
供应商
赞助商服务
的呼叫是为了便于使用,但感谢您的输入。