class Authority不是域类,或GORM尚未正确初始化或已被关闭

时间:2018-02-23 06:40:02

标签: grails spring-security gorm spring-security-rest

我正在研究grails rest app。我使用的grails版本是3.3.1。我正在使用spring-security-rest进行授权。我使用s2-quickstart命令创建了以下类。

  1. 用户
  2. 当局
  3. UserAuthority
  4. 应用程序运行正常,但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很新,所以我不知道可能出现什么问题。 我正在使用的课程是:

    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
    }
    }
    

1 个答案:

答案 0 :(得分:5)

通常在单元测试中,您测试单个单元,在这种情况下为User。因为您要测试其他实体,所以需要将它们添加到测试中。您可以通过实施getDomainClassesToMock来实现此目的。在这种情况下,最好使用DataTest特征而不是DomainUnitTestDomainUnitTest扩展DataTest)。

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

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

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