3

I'm working on a fresh Grails project and recently noticed the default convention in the Spring Security Core generated User class now auto-encodes the password via a beforeInsert/Update event. That's a nice, clean, DRY way of doing the encode, and also makes it impossible to forget to do so.

However, now when trying to write up some unit tests which make use of said User class, I find I either have to mock out the springSecurityService (due to the encode), or more preferably (and cleanly), I'd just override the beforeInsert/Update closure with one that does nothing. Typically in Groovy one can override a method using the ExpandoMetaClass, ala...

User.metaClass.beforeInsert = { /* do nothing */ }  

...but I'm finding that the original beforeInsert continues to be called upon creating and saving a new User. This in turn causes my unit tests to blow up. It's trivial for me to just work around this and mock out the service, but the above should work. Am I missing something? Is there something different with GORM's event closures that I'm not picking up on?

James
  • 1,391
  • 2
  • 14
  • 20
  • Another thing to note, I have a @Mock([User]) annotation on my test. This could have something to do with the odd behavior, but just a hunch so far. – James Dec 28 '12 at 21:34
  • Is the expando method on instance? // it is never too late to ask :) – Ivar Jun 18 '14 at 15:38
  • why do you think, that mocking out springSecurityService is not the preferred way doing it? i mean, one of the first things that is on the top of my head when thinking about dependency injection is exactly that: externalize dependecy management and so be able to create stubs / mock for testing purposes. In my opinion, to change the metaClass of User is not more clear in any way. – Mario David Jun 18 '14 at 19:27
  • 1
    @MarioDavid It's not a question about what is the right way to test it, that's a matter of opinion. It's a question about why overriding the beforeInsert does not work. I just happen to be using the above description to manifest the issue. – James Jun 19 '14 at 16:29

3 Answers3

2

In order to improve performance Grails uses reflection directly with caches method handles for invoking events and not Groovy's meta layer. The reason is that if you are saving hundreds of domain instances it can seriously hurt performance if Grails had to go through Groovy's meta layer for each event.

There are ways around this such as defining your own User class that disables the event based on a system/environment property that your test sets etc. but there is currently no way to override the methods via meta programming.

Graeme Rocher
  • 7,985
  • 2
  • 26
  • 37
  • I'm aware this is an old question. Is there some way to access the caching layer to override that method instead? – christopher May 11 '15 at 07:56
1

The beforeInsert closure actually is not only a method like toString() or save(), but also it is a pre-defined event supported by Gorm. Override the method will not prevent Gorm from firing the PreInsert event, which leads to the original process.

coderLMN
  • 3,076
  • 1
  • 21
  • 26
  • 2
    I'm aware beforeInsert is an event (see my last sentence) but the closure merely determines what *happens* when the event is fired for the given model. Overriding it should allow one to change that behavior just like anything else. I'm not trying to prevent GORM from firing the event, I'm trying to change what happens when the event is fired. – James Dec 29 '12 at 22:39
0

If necessary, you can replace the code in the beforeInsert with a private method and then override the private method

ice1080
  • 314
  • 3
  • 9