2014-04-24 69 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