[英]Grails Unit Test Null Strangeness
我在grails中有一組基本的單元測試,並且得到了一些奇怪的,不一致的行為。 因此,基本上,單元測試用於與我的用戶域進行交互的服務。
問題出在高水平-如果我運行完整的測試規范-每次4個測試都會失敗。 如果我單獨運行它們-它們會通過。 這里很明顯的事情是,測試之間保持着狀態-但是鑒於這是一個單元測試-不應存在(並且我已經通過記錄驗證了這一點)。
這里發揮的作用是:
因此,在查看規格時,我在設置中具有以下內容:
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")
}
基本上(縮短)了用戶域對象上的錯誤:
因此,您可以看到我在這些字段中使用了空字符串-並轉換為null(如Grails所做的那樣),這就是原因。 但是,問題在於:
nullable: true
約束中為nullable: true
因此,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"
您可以看到測試通過。
這個問題似乎是在skype
和phone
領域可以為空:第一次測試真實的,可為空:在第二次測試(我踏入假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.