gpt4 book ai didi

grails - 在 Controller 测试中创建的域对象不会在数据库中结束

转载 作者:行者123 更新时间:2023-12-01 15:37:00 25 4
gpt4 key购买 nike

我一直在尝试遵循 Grails in Action(GiA MEAP,第 2 版),但有时我会遇到一些问题,即使花了很多时间我似乎也无法弄清楚。这是其中之一。抱歉,这个问题与 GiA 中的示例相关( list 6.x 中的 v13、ch6、PostControllerSpec,第 144 页),但我将尝试使用精简但完整的代码来捕获问题。我有两个域模型,UserPost

package grailstuts

class User {
String loginId
static hasMany = [ posts: Post ]

static constraints = { loginId(blank: false, unique: true) }
}

package grailstuts

class Post {
String content
static belongsTo = [ user: User]

static constraints = { content(blank: false) }
}

PostController如下。

package grailstuts

class PostController {
static scaffold = true

def timeline() {
def user = User.findByLoginId(params.id)
if (!user) {
response.sendError(404)
} else {
[ user : user ]
}
}

def addPost() {
def user = User.findByLoginId(params.id)
if (user) {
def post = new Post(params)
user.addToPosts(post)
if (user.save()) {
flash.message = "Successfully created Post"
} else {
flash.message = "Invalid or empty post"
}
} else {
flash.message = "Invalid User Id"
}
redirect(action: 'timeline', id: params.id)
}
}

当我尝试按如下方式对 Controller 进行单元测试时(如书中所述),我遇到了问题。

package grailstuts

import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification

@TestFor(PostController)
@Mock([User,Post])
class PostControllerSpec extends Specification {

def "Adding a valid new post to the timeline"() {
given: "A user with posts in the db"
User chuck = new User(loginId: "chuck_norris").save(failOnError: true)

and: "A loginId parameter"
params.id = chuck.loginId

and: "Some content for the post"
params.content = "Chuck Norris can unit test entire applications with a single assert."

when: "addPost is invoked"
def model = controller.addPost()

then: "our flash message and redirect confirms the success"
flash.message == "Successfully created Post"
response.redirectedUrl == "/post/timeline/${chuck.loginId}"
Post.countByUser(chuck) == 1
}
}

测试通过了前两个测试 flash.message == "Successfully created Post"response.redirectedUrl == "/post/timeline/${chuck.loginId}",但在最后一行 Post.countByUser(chuck) == 1 失败(这非常令人费解,无法弄清楚失败的原因)。我得到以下信息:

|  Condition not satisfied:
Post.countByUser(chuck) == 1
| | |
0 | false
grailstuts.User : 1

我的问题是为什么上面的测试失败了,即使它成功创建了帖子?我花了很多时间试图找出错误,但还没有成功。

最佳答案

经过无数次尝试,我做了一些有效的事情。但是,我仍然很困惑,如果有人能解释一下,那真的很有帮助。如果 user.save()true,我为它所做的唯一更改是保存 post 显式 .这是修改后的 addPost()(唯一更改的行明确标记为 //save the post explicitly!!,其他地方没有其他更改)。

def addPost() {
def user = User.findByLoginId(params.id)
if (user) {
def post = new Post(params)
user.addToPosts(post)
if (user.save()) {
post.save(flush: true, failOnError: true) // save the post explicitly!!
flash.message = "Successfully created Post"
} else {
flash.message = "Invalid or empty post"
}
} else {
flash.message = "Invalid User Id"
}
redirect(action: 'timeline', id: params.id)
}

请注意:即使我执行了 if (user.save(flush: true)) 而不是 if (user.save()) 但没有包含将帖子显式保存为 post.save(flush: true, failOnError: true),它不起作用。我必须明确保存帖子。

因为保存 user 应该会自动保存 post ,这种行为仍然让我感到困惑。如果有人可以解释这种行为,那将非常有帮助。感谢那些花时间研究这个问题的人。



更新 --下面来自 Peter Ledbrook 的解释 ( link here ):

Which version of Grails are you using? I just tried with Grails 2.2.1 and got a NullPointerException in that test. Upgrading to 2.2.4 fixed that particular problem. Could be a Grails issue.

FYI, you shouldn't even need to explicitly save the User instance in the action to persist the Post. So something is definitely wrong. The cascading save is broken, probably in Grails' mock database implementation that's used during unit tests. I'm guessing that the application works fine when run normally (via run-app for example).

关于grails - 在 Controller 测试中创建的域对象不会在数据库中结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20688164/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com