2014-04-24 29 views
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 
    } 

} 

当我开始我并没有newing了我sponsorService,它不停地抱怨NULL的含量等等...我试图嘲笑(可能做错了),但...我需要测试对象使用的服务,所以...我不认为我需要一个模拟。

的服务看起来像:

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

回答

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方法更有意义。它简化了你的代码和你的测试。

+1

这绝对是一种可能!我会回去看看,看看其他一切是如何相互作用的。我还有其他一些事情不在这里。最初,从“Vendor”到“SponsoringService”的调用是为了方便使用,但感谢输入。 – buzzsawddog