views:

74

answers:

4

I have to unit test a method of a groovy class which uses sleep() to delay processing in a loop.

Obviously I don't want my test suite to sleep really, so I tried to mock the sleep() call in my class:

MyClass.metaClass.sleep = { return }

I tried a few variations of this with no success.

Can someone tell me the correct way to mock this language method?

+1  A: 

You could wrap all calls to system functions with an interface. This way you can mock calls to any method you would like. This does increase code complexity though, so you will have to decide if it is worth it.

Space_C0wb0y
That is one option but I really don't want to add complexity to my code to facilitate tests if I can help it.
Marek
@Marek: As pointed out [here](http://stackoverflow.com/questions/1007458/), this is a consequence of writing testable code. This is actually not a bad thing. However, it might be overkill in your case.
Space_C0wb0y
I realised right after I wrote that that it sounded bad. I agree with you, I just knew that in this particular case there would be a more succinct approach to solving the problem.
Marek
A: 

The code probably calls Thread.sleep doesn't it?

You can do this:

Thread.metaClass.static.sleep = { long time -> println "Sleep for $time" }

But I'm not sure it's what you want...

tim_yates
It actually just calls sleep. From what I can tell sleep is a static method added to all groovy objects as per: http://groovy.codehaus.org/groovy-jdk/java/lang/Object.html#sleep%28long%29 - I tried MyClass.metaClass.static.sleep = { return } too.
Marek
You learn something every day! :-D
tim_yates
Have you tried passing the argument type ie: `MyClass.metaClass.static.sleep = { long ms -> ms }` or `Object.metaClass.static.sleep = { long ms -> ms }`
tim_yates
It was passing the type explicitly that got this working for me. Good work!
Marek
A: 

This works for me:

class Foo {
    def longSleep() { sleep 10000000 }   
}

Foo.metaClass.sleep = { int ms -> println "no sleep" }
new Foo().longSleep()

Update from tim_yates: sleep(ms) is added to Object in the Groovy JDK. More info here: http://groovy.codehaus.org/groovy-jdk/java/lang/Object.html

xlson
Yeah, `sleep` is added to Object as a static convenience method, the same as `println` http://groovy.codehaus.org/groovy-jdk/java/lang/Object.html#sleep(long)
tim_yates
Ah, there it is. I knew I had seen it somewhere but couldn't find it yesterday, was looking at GroovyObjectSupport instead. Thanks :)
xlson
A: 

You need to be explicit in the arguments, and match the method you're overriding explicitly. Relying on the default "it" parameter doesn't work. Notice that overriding the static method only works when we state that the parameter is a "long" (and it's a static method, not an instance method):

def s = ""
def firstCalled = false
def secondCalled = true

s.metaClass.static.sleep = { firstCalled = true }

assert firstCalled == false

s.metaClass.static.sleep = { long ms -> firstCalled = true }

assert secondCalled == true
Ted Naleid
Others gave this solution but not as explicitly so I've marked this one as being the solution. I have no idea if that's how I'm meant to do it or not, but thanks to everyone for their help.
Marek
This is really what you should do, and by that I mean that you should put the mocked sleep method on the metaClass of an instance instead of the class itself :) foo.metaClass.sleep = ... instead of Foo.metaClass.sleep = ...
xlson