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

:

나는 다음과 같은 오류를 얻고있다. 다음과 같이

class Vendor { 
    def sponsorService 

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

그리고 내 테스트 설정은 다음과 같습니다 : 같은

Vendor 보이는

@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을 newing되지 않은 시작 때와는 nullness에 대해 불평 계속 그렇게 ... 내가 조롱을 시도했는데 (잘못된 일을했을 수도 있음) ... 서비스의 객체 사용을 테스트해야합니다 ... 나는 모의가 필요하다고 생각하지 않습니다.

이 서비스는 같이 보인다 :

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

이것은 확실히 가능합니다! 나는 돌아가서 한 번 훑어보고 다른 모든 것들이 상호 작용하는 방법을 보게 될 것이다. 여기에 포함되지 않은 몇 가지 다른 일들이있었습니다. 처음에 '공급 업체'에서 '스폰서링 서비스'로 전화하는 것은 사용하기 쉽도록하기위한 것이었지만 입력에 감사드립니다. – buzzsawddog

관련 문제