类权限不是域类或 GORM 未正确初始化或已关闭
Posted
技术标签:
【中文标题】类权限不是域类或 GORM 未正确初始化或已关闭【英文标题】:class Authority is not a domain class or GORM has not been initialized correctly or has already been shutdown 【发布时间】:2018-08-03 04:37:05 【问题描述】:我正在开发一个 grails rest 应用程序。我使用的 grails 版本是 3.3.1。我正在使用 spring-security-rest 进行授权。我使用 s2-quickstart 命令创建了以下类。
-
用户
权威
用户权限
应用程序运行良好,但用户类的单元测试失败,并在控制台中出现以下错误。
java.lang.IllegalStateException: Either class [hungr.Authority] is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.
at org.grails.datastore.gorm.GormEnhancer.stateException(GormEnhancer.groovy:469)
at org.grails.datastore.gorm.GormEnhancer.findStaticApi(GormEnhancer.groovy:300)
at org.grails.datastore.gorm.GormEnhancer.findStaticApi(GormEnhancer.groovy:296)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.currentGormStaticApi(GormEntity.groovy:1349)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.staticMethodMissing(GormEntity.groovy:756)
at hungr.UserController.$tt__save(UserController.groovy:39)
at hungr.UserController.save_closure1(UserController.groovy)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
at org.grails.testing.runtime.support.ActionSettingMethodHandler.invoke(ActionSettingMethodHandler.groovy:28)
at hungr.UserControllerSpec.Test the save action correctly persists(UserControllerSpec.groovy:90)
我试过参考GORM fails to realize Domain classes from a plugin are GORM classes的答案 但没有任何效果。我对 grails 很陌生,因此我不知道可能出了什么问题。 我正在使用的课程是:
User.Groovy
@GrailsCompileStatic
@EqualsAndHashCode(includes='username')
@ToString(includes='username', includeNames=true, includePackage=false)
class User implements Serializable, UserDetails
private static final long serialVersionUID = 1
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
String name
String email
Integer age
Boolean isVeg
byte[] profilePicture
String profilePictureContentType
String facebookId
String facebookProfilePictureUrl
boolean isFacebookUser
static hasMany = [notifications: Notification, posts: DiaryItem, comments: Comment]
Set<Authority> getAuthorities()
(UserAuthority.findAllByUser(this) as List<UserAuthority>)*.authority as Set<Authority>
@Override
boolean isAccountNonExpired()
return !accountExpired
@Override
boolean isAccountNonLocked()
return !accountLocked
@Override
boolean isCredentialsNonExpired()
return !passwordExpired
static constraints =
password nullable: false, blank: false, password: true
username nullable: false, blank: false, unique: true
facebookId nullable: true
name nullable: false, blank: false, maxSize: 100
email blank: false, email: true
age nullable: false, min: 8
isVeg nullable: false
profilePicture nullable: true, maxSize: 1073741824
profilePictureContentType nullable: true
isFacebookUser nullable: false
facebookProfilePictureUrl nullable: true, maxSize: 1000
static mapping =
password column: '`password`'
Authority.Groovy
@GrailsCompileStatic
@EqualsAndHashCode(includes='authority')
@ToString(includes='authority', includeNames=true, includePackage=false)
class Authority implements Serializable, GrantedAuthority
private static final long serialVersionUID = 1
String authority
static constraints =
authority nullable: false, blank: false, unique: true
static mapping =
cache true
UserAuthority.Groovy
@GrailsCompileStatic
@ToString(cache=true, includeNames=true, includePackage=false)
class UserAuthority implements Serializable
private static final long serialVersionUID = 1
User user
Authority authority
@Override
boolean equals(other)
if (other instanceof UserAuthority)
other.userId == user?.id && other.authorityId == authority?.id
@Override
int hashCode()
int hashCode = HashCodeHelper.initHash()
if (user)
hashCode = HashCodeHelper.updateHash(hashCode, user.id)
if (authority)
hashCode = HashCodeHelper.updateHash(hashCode, authority.id)
hashCode
static UserAuthority get(long userId, long authorityId)
criteriaFor(userId, authorityId).get()
static boolean exists(long userId, long authorityId)
criteriaFor(userId, authorityId).count()
private static DetachedCriteria criteriaFor(long userId, long authorityId)
UserAuthority.where
user == User.load(userId) &&
authority == Authority.load(authorityId)
static UserAuthority create(User user, Authority authority, boolean flush = false)
def instance = new UserAuthority(user: user, authority: authority)
instance.save(flush: flush)
instance
static boolean remove(User u, Authority r)
if (u != null && r != null)
UserAuthority.where user == u && authority == r .deleteAll()
static int removeAll(User u)
u == null ? 0 : UserAuthority.where user == u .deleteAll() as int
static int removeAll(Authority r)
r == null ? 0 : UserAuthority.where authority == r .deleteAll() as int
static constraints =
user nullable: false
authority nullable: false, validator: Authority r, UserAuthority ur ->
if (ur.user?.id)
if (UserAuthority.exists(ur.user.id, r.id))
return ['userRole.exists']
static mapping =
id composite: ['user', 'authority']
version false
编辑 1: 单元测试类是:
class UserControllerSpec extends Specification implements
ControllerUnitTest<UserController>, DomainUnitTest<User>
def populateValidParams(params)
assert params != null
// TODO: Populate valid properties like...
//params["name"] = 'someValidName'
params["username"]
params["password"]
params["name"] = "User"
params["email"] = "user@hungr.com"
params["age"] = 19
params["isVeg"] = false
// new MockMultipartFile('profilePicture', 'myImage.jpg', imgContentType, imgContentBytes)
// def multipartFile = new GrailsMockMultipartFile('profilePicture', 'profilePicture.jpg', 'image/jpeg', new byte[0])
//request.addFile(multipartFile)
// params["profilePicture"] =// new MockMultipartFile('profilePicture', 'file.jpg', 'image/jpeg', "1234567" as byte[])
params["profilePictureContentType"] = "image/jpeg"
params["facebookId"] = "fb_id"
params["facebookProfilePictureUrl"] = "http://abc.def"
params["isFacebookUser"] = true
//assert false, "TODO: Provide a populateValidParams() implementation for this generated test suite"
void "Test the index action returns the correct model"()
given:
controller.userService = Mock(UserService)
1 * list(_) >> []
1 * count() >> 0
when:"The index action is executed"
controller.index()
then:"The model is correct"
!model.userList
model.userCount == 0
void "Test the create action returns the correct model"()
when:"The create action is executed"
controller.create()
then:"The model is correctly created"
model.user!= null
void "Test the save action with a null instance"()
when:"Save is called for a domain instance that doesn't exist"
request.contentType = FORM_CONTENT_TYPE
request.method = 'POST'
request.format = 'form'
controller.save(null)
then:"A 404 error is returned"
response.redirectedUrl == '/user/index'
flash.message != null
void "Test the save action correctly persists"()
given:
controller.userService = Mock(UserService)
1 * save(_ as User)
when:"The save action is executed with a valid instance"
response.reset()
request.contentType = FORM_CONTENT_TYPE
request.method = 'POST'
request.format = 'form'
byte[] b = new byte[1]
b[0]= 123
request.addFile(new MockMultipartFile('profilePicture', 'file.jpg', 'image/jpeg', b))
populateValidParams(params)
def user = new User(params)
user.id = 1
controller.save(user)
then:"A redirect is issued to the show action"
response.redirectedUrl == '/user/show/1'
controller.flash.message != null
void "Test the save action with an invalid instance"()
given:
controller.userService = Mock(UserService)
1 * save(_ as User) >> User user ->
throw new ValidationException("Invalid instance", user.errors)
when:"The save action is executed with an invalid instance"
request.contentType = FORM_CONTENT_TYPE
request.method = 'POST'
def user = new User()
controller.save(user)
then:"The create view is rendered again with the correct model"
model.user != null
view == 'create'
void "Test the show action with a null id"()
given:
controller.userService = Mock(UserService)
1 * get(null) >> null
when:"The show action is executed with a null domain"
controller.show(null)
then:"A 404 error is returned"
response.status == 404
void "Test the show action with a valid id"()
given:
controller.userService = Mock(UserService)
1 * get(2) >> new User()
when:"A domain instance is passed to the show action"
controller.show(2)
then:"A model is populated containing the domain instance"
model.user instanceof User
void "Test the edit action with a null id"()
given:
controller.userService = Mock(UserService)
1 * get(null) >> null
when:"The show action is executed with a null domain"
controller.edit(null)
then:"A 404 error is returned"
response.status == 404
void "Test the edit action with a valid id"()
given:
controller.userService = Mock(UserService)
1 * get(2) >> new User()
when:"A domain instance is passed to the show action"
controller.edit(2)
then:"A model is populated containing the domain instance"
model.user instanceof User
void "Test the update action with a null instance"()
when:"Save is called for a domain instance that doesn't exist"
request.contentType = FORM_CONTENT_TYPE
request.method = 'PUT'
controller.update(null)
then:"A 404 error is returned"
response.redirectedUrl == '/user/index'
flash.message != null
void "Test the update action correctly persists"()
given:
controller.userService = Mock(UserService)
1 * save(_ as User)
when:"The save action is executed with a valid instance"
response.reset()
request.contentType = FORM_CONTENT_TYPE
request.method = 'PUT'
request.format = 'form'
request.addFile(new MockMultipartFile('profilePicture', 'file.jpg', 'image/jpeg', "1234567" as byte[]))
populateValidParams(params)
def user = new User(params)
user.id = 1
controller.update(user)
then:"A redirect is issued to the show action"
response.redirectedUrl == '/user/show/1'
controller.flash.message != null
void "Test the update action with an invalid instance"()
given:
controller.userService = Mock(UserService)
1 * save(_ as User) >> User user ->
throw new ValidationException("Invalid instance", user.errors)
when:"The save action is executed with an invalid instance"
request.contentType = FORM_CONTENT_TYPE
request.method = 'PUT'
controller.update(new User())
then:"The edit view is rendered again with the correct model"
model.user != null
view == 'edit'
void "Test the delete action with a null instance"()
when:"The delete action is called for a null instance"
request.contentType = FORM_CONTENT_TYPE
request.method = 'DELETE'
controller.delete(null)
then:"A 404 is returned"
response.redirectedUrl == '/user/index'
flash.message != null
void "Test the delete action with an instance"()
given:
controller.userService = Mock(UserService)
1 * delete(2)
when:"The domain instance is passed to the delete action"
request.contentType = FORM_CONTENT_TYPE
request.method = 'DELETE'
controller.delete(2)
then:"The user is redirected to index"
response.redirectedUrl == '/user/index'
flash.message != null
【问题讨论】:
请添加您的单元测试 @DenniedeLange 添加。 【参考方案1】:所以通常在单元测试中你测试一个单元,在这种情况下是User
。因为要测试其他实体,所以需要将它们添加到测试中。您可以通过实现getDomainClassesToMock
来做到这一点。在这种情况下最好使用DataTest
trait 而不是DomainUnitTest
(DomainUnitTest
扩展DataTest
)。
所以你的测试应该是这样的:
class UserControllerSpec extends Specification implements
ControllerUnitTest<UserController>, DataTest
Class<?>[] getDomainClassesToMock()
return [User,Authority,UserAuthority] as Class[]
....
【讨论】:
以上是关于类权限不是域类或 GORM 未正确初始化或已关闭的主要内容,如果未能解决你的问题,请参考以下文章