grails - 类权限不是域类或 GORM 尚未正确初始化或已关闭

标签 grails spring-security grails-orm spring-security-rest

我正在开发一个 Grails Rest 应用程序。我使用的grails版本是3.3.1。我正在使用 spring-security-rest 进行授权。我使用 s2-quickstart 命令创建了以下类。

  1. 用户
  2. 权威
  3. 用户权限

应用程序运行良好,但 User 类的单元测试失败,并在控制台中出现以下错误。

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 还很陌生,因此我不知道可能出了什么问题。 我正在使用的类是:

用户.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`'
}
}

权威.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
}
}

最佳答案

因此,通常在单元测试中,您会测试单个单元,在本例中为User。因为您想要测试其他实体,所以需要将它们添加到测试中。您可以通过实现getDomainClassesToMock来做到这一点。在这种情况下,最好使用 DataTest 特征而不是 DomainUnitTest(DomainUnitTest extends DataTest)。

所以你的测试应该是这样的:

class UserControllerSpec extends Specification implements          
ControllerUnitTest<UserController>, DataTest {

    Class<?>[] getDomainClassesToMock(){
        return [User,Authority,UserAuthority] as Class[]
    }
    .... 
}

关于grails - 类权限不是域类或 GORM 尚未正确初始化或已关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48942474/

相关文章:

javascript - 无法解析日期 javascript 到 Grails

java - 使用 OAuth2 从 Spring Security 自定义身份验证错误

spring-boot - Spring Boot OAuth2 invalid_user_info_response

grails - 允许通过 grails/gorm 中的配置更改表名的正确方法是什么

java - chalice /hibernate : No row with the given identifier exists

hibernate - 在 GORM 中查询关联的子查询

javascript - 在 Grails 的 JavaScript 源代码中执行 groovy 语句

grails - 如何更改默认的message.properties

tomcat - 如何找到tomcat网络应用程序的网址?

java - 使用 spring-security-saml 在应用程序中没有配置 IDP 错误