views:

289

answers:

2

I'm trying to use groovy's MockFor and proxyDelegateInstance to mock a java class with constructor parameters, but I can't seem to get it right. My Java class looks like:

class MyJavaClass {
   private MyObject myObj
   public MyJavaClass(MyObject myObj) {
      this.myObj = myObj;
   }
}

class MyGroovyTest {
    @Test
    void testMyJavaClass() {
        def mock = new MockFor(MyJavaClass)
        MyJavaClass mjc = new MyJavaClass()
        def mockProxy = mock.proxyDelegateInstance([mjc] as Object[])
        // if I pass mockProxy to anything, I get an error that a matching 
        // constructor could not be found. I've tried variations on the args 
        // to proxyDelegateInstance (such as using mjc as a single arg rather than 
        // an array of one element)
    }

}

Can I actually do this in groovy? And if so, how can I do it?

thanks, Jeff

A: 

I can't tell you why you're code above is not working, but there are several ways in Groovy to mock Java classes without using MockFor. For example, if you want to intercept all calls to the object, you can implement invokeMethod on the classes' metaClass, e.g.

class SomeJavaClass {
  // methods not shown
}

def instance = new SomeJavaClass()

instance.metaClass.invokeMethod = {String name, args ->
  // this will be called for all methods invoked on instance
}

Alternatively, if you simply want to provide an object that supports the method signatures of SomeJavaClass, you could use either a Map or an Expando with properties where:

  • property names match method names
  • proprerty values are closures that accept the same parameters as methods

If you can provide a bit more information about how the mock object is used, perhaps I can provide some more specific suggestions.

Don
Don, the problem is if I have another class, let's call it Actor, that takes a MyJavaClass as a parameter and I call actor.doSomething(mockProxy) I get an error about not having the appropriate constructor to create MyJavaClass.
Jeff Storey
If Actor is not actually instantiating MyJavaClass, then could you just instantiate MyJavaClass normally, and use `invokeMethod` to override the method implementations?
Don
At the end of the test, I need to verify MyJavaClass, which is why I've created it as a mock.
Jeff Storey
I think the issue is that proxyDelegateInstance doesn't actually return an instanceof the class, rather it returns a class of type class_delegateProxy. This will work in groovy because of the dynamic typing but passing this to a Java class won't work (if this is the problem) since Java is checking the type.
Jeff Storey
I meant because of Groovy's duck-typing (not dynamic typing, though groovy is dynamically typed of course) above
Jeff Storey
Have you tried using the `proxyInstance` method rather than `proxyDelegateInstance`?
Don
Yes. I confirmed that the issue is in fact because my class is a class and the proxyXXX methods return something that is not actually of that class type (for classes only though, works for interfaces)
Jeff Storey
A: 

The problem was that the class being mocked was a class and not an interface. In order to use the proxyDelegateInstance method, the an interface type needs to be used (or a groovy class). The proxy class is not actually of the MyJavaClass type but is a proxy and groovy's duck typing can handle that while Java cannot.

Jeff Storey