簡體   English   中英

Grails單元測試無效性

[英]Grails Unit Test Null Strangeness

我在grails中有一組基本的單元測試,並且得到了一些奇怪的,不一致的行為。 因此,基本上,單元測試用於與我的用戶域進行交互的服務。

問題出在高水平-如果我運行完整的測試規范-每次4個測試都會失敗。 如果我單獨運行它們-它們會通過。 這里很明顯的事情是,測試之間保持着狀態-但是鑒於這是一個單元測試-不應存在(並且我已經通過記錄驗證了這一點)。

這里發揮的作用是:

  • UserService
  • 用戶域
  • 地址域
  • UserCommand(可驗證)

因此,在查看規格時,我在設置中具有以下內容:

User user

def setup() {

    println "================ Setting Up User (${User.count()}) ================"

    // Set the roles
    new Role(authority: "ROLE_ADMIN").save()
    new Role(authority: "ROLE_OPERATOR").save()
    def role = new Role(authority: "ROLE_USER").save()

    def userAddress = new Address()
    userAddress.with {
        name = "Name"
        address1 = "Address 1"
        address2 = "Address 2"
        townCity = "Town"
        postcode = "BT19"
        county = "Down"
    }

    // Create an admin user
    user = new User()
    user.with {
        christianName = "Phil"
        surname = "Preston"
        email = "p@p.com"
        username = "admin"
        password = "password123"
        phone = ""
        skype = ""
        address = userAddress
    }

    println(user.properties)

    // Save the test user
    if (user.validate()) {
        println "Saving"
        user.save(flush: true, failOnErrors: true)
        UserRole.create(user, role)
    }
    else {
        user.errors.allErrors.eachWithIndex { i, x ->
            println "${i} - ${x}"
        }
    }


    assert user
}

兩個簡單的測試如下:

void "Test updateUser - changing a user password"() {

    given: "An update to the user"
    UserCommand cmd = new UserCommand()
    cmd.with {
        id = user.id
        christianName = user.christianName
        surname = user.surname
        username = user.username
        email = user.email
        skype = user.skype
        phone = user.phone
        password = "newPassword"
        passwordCheck = "newPassword"
        isAdmin = user.isAdmin()
        isOperator = user.isOperator()
    }

    when: "attempt to update"
    User updated = service.updateUser(cmd)

    then: "the password should be update - but nothing else"
    updated.password == cmd.password
}

void "Test updateUser - changing a user detail"() {

    given: "An update to the user"
    UserCommand cmd = new UserCommand()
    cmd.with {
        id = user.id
        christianName = user.christianName
        surname = user.surname
        username = user.username
        email = "update@update.com"
        skype = user.skype
        phone = user.phone
        password = user.password
        isAdmin = user.isAdmin()
        isOperator = user.isOperator()
    }

    when: "attempt to update"
    User updated = service.updateUser(cmd)

    then: "the email should be update - but nothing else"
    updated.email == cmd.email
}

(還有其他人-但這全都可以證明問題所在)

因此,奇怪之處如下:

  • 第一次測試通過,第二次失敗。
  • 如果我調換訂單-第一個仍然通過,第二個失敗
  • 如果我兩個人都跑-他們都會通過
  • setup()的代碼每次都會打印用戶對象(0)的數量
  • 它驗證每次創建對象( assert和記錄)

單元測試失敗,因為當我要驗證的用戶域對象的驗證失敗時,我拋出異常。 因此,以下內容:

def updateUser(UserCommand userCommand) {
    assert userCommand

    // Get the current
    User foundUser = User.findById(userCommand.id)
    def wasAdmin = foundUser.admin
    def wasOperator = foundUser.operator

    // Bind Data
    bindData(foundUser, userCommand, ['class', 'operator', 'admin', 'address'])
    foundUser?.address?.with {
        name = userCommand.name
        address1 = userCommand.address1
        address2 = userCommand.address2
        townCity = userCommand.townCity
        county = userCommand.county
        postcode = userCommand.postcode
    }

    // THIS VALIDATION FAILS ON SECOND TEST
    if (foundUser.validate()) {
        foundUser.save() 
        // ... removed 
        return foundUser.refresh()
    }
    else {
        Helper.copyErrorToCmd(foundUser, userCommand)
        log.error("Errors: ${foundUser.errors.allErrors}")
        throw new UserServiceException(cmd: userCommand, message: "There were errors updating user")
    }

基本上(縮短)了用戶域對象上的錯誤:

  • 'skype':拒絕值[null]
  • “電話”:拒絕值[null]

因此,您可以看到我在這些字段中使用了空字符串-並轉換為null(如Grails所做的那樣),這就是原因。 但是,問題在於:

  • 兩者都應該失敗,並且當單獨運行時肯定會失敗
  • 兩個字段都標記為nullable: true約束中為nullable: true
  • 在UserService中,我使用調試器檢查了運行兩個測試時正在保存的對象-電話和skype在兩個測試中均為null,但一個失敗而一個沒有

因此,User域對象中的約束如下:

static constraints = {
    christianName blank: false
    surname blank: false
    username blank: false, unique: true, size: 5..20
    password blank: false, password: true, minSize: 8
    email email: true, blank: false
    phone nullable: true
    skype nullable: true
    address nullable: true
}

我正在使用具有以下約束的Command對象:

static constraints = {
    importFrom User
    importFrom Address
    password blank: false, password: true, minSize: 8
    passwordCheck(blank: false, password: true, validator: { pwd, uco -> return pwd == uco.password })
}

注意,我什至嘗試在UserCommand約束閉包中添加Skype和phone字段。

如果我在setup的字段中添加文本,此問題就消失了,但是在實際應用中這不可能,因為這些字段可以留空。

任何有關這種不一致情況如何發生的幫助將不勝感激。

娛樂

我添加了一個最小的GitHub項目,它重新創建了該問題: Github Project Recreating Issue 要查看問題:

./grailsw test-app

將運行兩次測試,第一次通過第二次失敗。 要單獨運行失敗的測試,請運行:

./gradlew test --tests "org.arkdev.bwmc.accountmission.UserServiceSpec.*Test updateUser - changing a user detail"

您可以看到測試通過。

這個問題似乎是在skypephone領域可以為空:第一次測試真實的,可為空:在第二次測試(我踏入假user.validate()並步入GrailsDomainClassValidator.java ,在validate(Object,Errors,boolean)調用我可以看到constrainedProperties Map(基本上是字段->約束),這表明在第一次調用setup時,Skype為NullableConstraint.nullable == true ,但顯示NullableConstraint.nullable == false在第二次測試的設置調用中為NullableConstraint.nullable == false 。)。 這是沒有道理的。

您不必從技術上測試框架中的約束,但之前我遇到過類似的問題,因此我可以了解您為什么要這樣做。

是否可以發布您的完整測試? 您是否正在使用@ TestFor / @ Mock? 就像檢查一樣,但是我認為您必須具有@Mock,否則創建域類會遇到其他錯誤? 使用約束需要@Mock(或@GrailsUnitTestMixin afaik)。

您在評論中說“應用程序中的值可以為空”; 應該注意的是,這與可空值也不相同。 如果確實可以空白,則應更改/添加它,然后“”將起作用

您也沒有使用'failOnError:true',因為已經輸入了錯誤。

抱歉,我沒有足夠的代表來撰寫評論。

第一次通話后

bindData(foundUser, userCommand, ['class', 'operator', 'admin', 'address'])

UserService.updateUser(UserCommand) (通過功能方法Test updateUser - changing a user password調用)中,靜態成員User.constraints變為null 去搞清楚。 我不知道Grails是如何工作的,所以也許其他人也可以理解。 但是在我看來,這不應該發生。 也許您以某種方式在通話中犯了一個錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM