测试域类中的服务

时间:2014-04-24 14:20:00

标签: 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:111)
        at some.vendor.Vendor2Spec.Test a sponsor(Vendor2Spec.groovy:29)
|Completed 1 unit test, 1 failed in 0m 3s
.................Tests FAILED

在下面的代码中,我已经指出了我们的行号,它们被称为错误。

我的Vendor看起来像是:

class Vendor {
  def sponsorService

  SponsorLevel getSponsorLevel(){
    return sponsorService.getLevel(this)  // Line 111
  }
}

我的测试设置如下:

@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
  }

}

当我刚开始的时候,我并没有在我的sponsorService上做新的事情而且它一直在抱怨零点所以......我试着嘲笑(可能做错了)但是...我需要测试对象使用该服务所以...我不认为我需要一个模拟。

该服务如下:

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
  }
}

1 个答案:

答案 0 :(得分:2)

一般来说,从其他类调用单元测试时,应该模拟服务类,否则,你需要编写集成测试。

就个人而言,如果这就是你所有的服务,我只是在域名上做一个方法:

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()没有对数据库执行任何操作,并且该方法特定于您的供应商域。所以对我来说,在Vendor上创建一个Domain方法更有意义。它简化了您的代码和测试。