我正在尝试为我的一个域类编写单元测试。我作弊,我知道代码使用代码工作但是...我想确保我有一些自动化测试。
我收到以下错误:
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
}
}
答案 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方法更有意义。它简化了您的代码和测试。