I have huge class that I need to build stub for.
To give you picture it is Messages class of the GWT. Often this is class with dozens of methods that return String.
With JMock I can do stubbing, but I will end with allowing each method... This is not something that I would like to see.
Is there something that will automatically build the stubs for each method? I need this methods to return something predefined, like empty string, but I will be happy with any suggestions.
In JMock you can allow the methods you care about with explicit results and then allow any other method of the messages object with an allowing statement that does not include a method. E.g.:
allowing(m).getBlah("something");
will(returnValue("foo"));
allowing(m); // matches anything else, will return some default value if called
But...
If you are just stubbing a bunch of getter methods, a mock object framework is the wrong tool to use. Mock objects are used for testing that the object under test sends the correct commands to neighbouring objects to effect change in its environment.
It's often easier to create a stub class if the interface that only contains getters. Or you can use Usurper to generate stubs automatically.
For an interface you can use the functionality of java.lang.reflect.Proxy. Assuming that you want to stub answers for the MessageConstants class, the code will look similar to:
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (String.class.equals(method.getReturnType()))
return "proxy generated method return";
throw new AbstractMethodError("Not implemented");
}
};
Class<?> proxyClass = Proxy.getProxyClass(MessageConstants.class.getClassLoader(), new Class[] { MessageConstants.class });
MessageConstants messageConstants = (MessageConstants) proxyClass.getConstructor(new Class[] {InvocationHandler.class}).newInstance(new Object[] { handler });
System.out.println(messageConstants.description());
messageConstants.getBoolean("someBoolean");
and will result in
proxy generated method return
Exception in thread "main" java.lang.Error: Not implemented
at xxx.Application$1.invoke(Application.java:48)
at $Proxy0.getBoolean(Unknown Source)
at xxx.Application.main(Application.java:64)
The InvocationHandler drives the stubbing, while the rest is just plumbing.
Glad to see you found an answer. Just for further info, jMock allows quite flexible specifications of how you match methods, see http://www.jmock.org/match-object-or-method.html. For example, you can do this sort of thing:
allowing (any(Object.class)).method("get.*").withNoArguments();
to match any getter.
S
If you use EasyMock, you only need to specify behavior/expectations/stubs for the methods you actually expect to be called and used.
After using both JMock and EasyMock, I have to say that EasyMock's API is about 10x easier to use, and since the interface is mostly statically-typed, it's refactoring safe as well (you are using Strings for method names, etc.).
Related
I have a a static method in some legacy code, which is called by multiple clients. I obviously have no options to override it, or change behaviour through dependency injection. I am not allowed to modify the existing class.
What I want to do now is change the behaviour (that method - with the same signature and return type) using reflection.
Is it possible ? If not, can any design pattern rescue me ?
Thanks !
EDIT : There is some confusion on what can I change/modify. I cannot change any existing class/method - but I can add more classes to the project. The best I can do with the existing classes is annotate them. This is all done to avoid breaking anything in the existing code - which means a complete round of testing for a big project.
EDIT 2 : java.lang.Instrumentation is not available for Android - or else it sounds like a good fit !
Sounds like a weird requirement...
Anyway, reflection does not allow you to change code behaviour, it can only explore current code, invoke methods and constuctors, change fields values, that kind of things.
If you want to actually change the behaviour of a method you would have to use a bytecode manipulation library such as ASM. But this will not be very easy, probably not a good idea...
Patterns that might help you :
If the class is not final and you can modify the clients, extend the existing class and overload the method, with your desired behaviour. Edit : that would work only if the method were not static !
Aspect programming : add interceptors to the method using AspectJ
Anyway, the most logical thing to do would be to find a way to modify the existing class, work-arounds will just make your code more complicated and harder to maintain.
Good luck.
I guess you could have a look at Instrumentation class which have a method redefineClasses(ClassDefintion classDefinition).
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.
Hope this helps.
References: Javadoc
You can change method behaviour via Java's dynamic proxies mechanism. See this guide.
It will proxied all object methods. You can redefine only some methods by method name, like:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("put")) { // example for map
methods.get(method.getName()).invoke(target, args);
args[0] = "second"; // put again with "second" key
Object result = methods.get(method.getName()).invoke(target, args);
return result;
}
if (method.getName().equals("get")) { // example for map
System.out.println("Method get"); // you implementation
return methods.get(method.getName()).invoke(target, args);
}
return methods.get(method.getName()).invoke(target, args); // just do what initial method do
}
I have a a static method in some legacy code, which is called by multiple clients. I obviously have no options to override it, or change behaviour through dependency injection. I am not allowed to modify the existing class.
What I want to do now is change the behaviour (that method - with the same signature and return type) using reflection.
Is it possible ? If not, can any design pattern rescue me ?
Thanks !
EDIT : There is some confusion on what can I change/modify. I cannot change any existing class/method - but I can add more classes to the project. The best I can do with the existing classes is annotate them. This is all done to avoid breaking anything in the existing code - which means a complete round of testing for a big project.
EDIT 2 : java.lang.Instrumentation is not available for Android - or else it sounds like a good fit !
Sounds like a weird requirement...
Anyway, reflection does not allow you to change code behaviour, it can only explore current code, invoke methods and constuctors, change fields values, that kind of things.
If you want to actually change the behaviour of a method you would have to use a bytecode manipulation library such as ASM. But this will not be very easy, probably not a good idea...
Patterns that might help you :
If the class is not final and you can modify the clients, extend the existing class and overload the method, with your desired behaviour. Edit : that would work only if the method were not static !
Aspect programming : add interceptors to the method using AspectJ
Anyway, the most logical thing to do would be to find a way to modify the existing class, work-arounds will just make your code more complicated and harder to maintain.
Good luck.
I guess you could have a look at Instrumentation class which have a method redefineClasses(ClassDefintion classDefinition).
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, or change inheritance.
Hope this helps.
References: Javadoc
You can change method behaviour via Java's dynamic proxies mechanism. See this guide.
It will proxied all object methods. You can redefine only some methods by method name, like:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("put")) { // example for map
methods.get(method.getName()).invoke(target, args);
args[0] = "second"; // put again with "second" key
Object result = methods.get(method.getName()).invoke(target, args);
return result;
}
if (method.getName().equals("get")) { // example for map
System.out.println("Method get"); // you implementation
return methods.get(method.getName()).invoke(target, args);
}
return methods.get(method.getName()).invoke(target, args); // just do what initial method do
}
I'm using mockito and developping with java6 and spring.
I'm working on a test API for some developpers and I propose a few methods for mocking objects and methods (it's a legacy code...).
Now, I want to replace all this things by mockito but I always propose a test API. So, I developped some methods using mockito.
I have an old method with two parameters (String). A first parameter is a mocked service id and its method with parameters. And the second parameter is the returned Object.
Example :
mockReturnObject("myServiceId.myMethod(String, Integer)", myReturnedObject);
Now, I want to use mock, when and thenReturn mockito methods, and I don't see how...
Perhaps with reflection but with "when" method it's impossible because mockito need the effective method.
How can I do that ? thanks.
This is a bad idea: you're trying to reimplement some of the systems Mockito already provides while losing out on many of the features Mockito offers. However, there is a way to make this work, with some difficulty. The key is to write a custom Answer, make it the default answer for the mock, and then compare your object, method name, and method parameter types using InvocationOnMock.
public class ReflectiveMockAnswer implements Answer<Object> {
#Override public Object answer(InvocationOnMock invocation) {
// Assume you've successfully parsed each String into a StubbedResponse, with
// Object target, String method, String[] argTypes, and Object returnValue.
// A Set would beat a for-loop here, should you need to optimize.
for (StubbedResponse stubbedResponse : allStubbedResponses) {
if (stubbedResponse.target == invocation.getMock()
&& stubbedResponse.method.equals(invocation.getMethod().getName())
&& stringArraysEqual(stubbedResponse.argTypes,
typeNamesFrom(invocation.getMethod().getParameterTypes())) {
return stubbedResponse.returnValue;
}
}
throw new RuntimeException("Unstubbed method called.");
}
}
// Later...
Object yourMockObject = Mockito.mock(classToMock, new ReflectiveMockAnswer());
At that point, you've implemented a simplified version of Mockito within and based on the full version of Mockito. You'll also need to:
Parse the string into a StubbedResponse, probably with regular expressions
Identify the field in your bean-under-test by name
Replace that field with a mock of the appropriate class, created as above, before the bean-under-test has a chance to interact with it
...and acknowledge that this solution doesn't handle:
Verification
Any sort of argument matching, including basic "equals" matching
Name collisions in parameter types (com.foo.SomeClass vs com.bar.SomeClass)
Repeated calls (thenReturn(1, 2, 3).thenThrow(new RuntimeException()))
...and cannot handle:
Code search tools: you can only tell which methods are mocked other than by searching for strings, not with tools like "Find references" in Eclipse the way Mockito can
Compile-time checking and automated refactoring tools: your tests would break at runtime if field names, method names, or parameters change; Mockito doesn't have that problem
Final methods: Mockito can't, so you can't either
Unless this is a "straw man" or very temporary solution, I recommend strongly to just introduce Mockito directly into your test cases, one test at a time.
So my class under test has code that looks braodly like this
public void doSomething(int param)
{
Report report = new Report()
...do some calculations
report.someMethod(someData)
}
my intention was to extract the construction of report into a protected method and override it to use a mock object that I could then test to ensure that someMethod had been called with the right data.
So far so good. But Report isnt under my control, and to mkae things worse it uses JNI to load a library at runtime.
If I do
Report report = EasyMock.createMock(Report.class)
then EasyMock attempts to use reflection to find out the class members, but this causes an attempt to load the JNI library, which fails (the JNI libraries are only available on UNIX).
Im considering two things: a) Introduce a ReportWrapper interface with two implementations, one of which will delegate calls to an real Report (so basically a Proxy), and a second which will basically use a mock object. or b) instead of calling someMethod, call a protected method which will in turn call someMethod that I can override in a testing subclass.
Either way it seems nasty. Any better ways?
If there's no interface to Report class, then your suggested wrapper is the correct approach.
The book "Refactoring: Improving the Design of Existing Code" has a chapter about extracting interfaces from badly designed classes.
If you're using some DI framework (e.g. SpringFramework) you can easily replace this object with some ObjectFactory to create the correct implementation (mock vs. real one).
With EasyMock, you would have to resort to some form of refactoring. The only way to avoid it would be to use a mocking tool which can mock internally created objects. With JMockit (a tool I develop), the test could be written like this:
public void testDoSomething(final Report mockedReport)
{
// create "someData"
objectUnderTest.doSomething(123);
new Verifications() {{ mockedReport.someMethod(someData); }};
}
I want to intercept all method invocations to some class MyClass to be able to react on some setter-invocations.
I tried to use dynamic proxies, but as far as I know, this only works for classes implementing some interface. But MyClass does not have such an interface.
Is there any other way, besides implementing a wrapper class, that delegates all invocations to a member, which is an instance of the MyClass or besided using AOP?
As you note, you cannot use JDK dynamic proxies (no interface), but using Spring and CGLIB (JAR included with Spring), you can do the following:
public class Foo
{
public void setBar()
{
throw new UnsupportedOperationException("should not go here");
}
public void redirected()
{
System.out.println("Yiha");
}
}
Foo foo = new Foo();
ProxyFactory pf = new ProxyFactory(foo);
pf.addAdvice(new MethodInterceptor()
{
public Object invoke(MethodInvocation mi) throws Throwable
{
if (mi.getMethod().getName().startsWith("set"))
{
Method redirect = mi.getThis().getClass().getMethod("redirected");
redirect.invoke(mi.getThis());
}
return null;
}
});
Foo proxy = (Foo) pf.getProxy();
proxy.setBar(); // prints "Yiha"
If you are prepared to do something really ugly, have a look at:
http://docs.oracle.com/javase/7/docs/technotes/guides/jpda/
Basically the debugger interface ought to allow you to attach like a debugger, and hence intercept calls. Bear in mind I think this is a really bad idea, but you asked if it was possible.
Java doesn't have any actual language features for method interception (not sure any static language does)
I kinda like Nick's idea of using the debugger interface, that's just mean.
I think the short answer you need is: No there isn't a way of intercepting a method call in Java without actually replacing the class using a proxy or wrapper.
Note: The AOP libraries just make this happen automatically.
Some of the Java gurus might frown upon this but I've had some good success with avoiding primitive types and setters altogether. My class looks like this:
class Employee extends SmartPojo {
public SmartString name;
public SmartInt age;
}
You'll notice two things: 1. everything is public. 2. No constructor.
The magic happens in SmartPojo which searches for any field which implements the "Smart" interface and initializes it. Since this is no primitive (and no final class), I can add set() and get() methods for all fields anywhere in my model in a single place. So no setter/getter wastes anymore, it's stunningly simple to add notification (also in a single place), etc.
True, this is no POJO anymore and it's not a Bean in most ways but I've found that these old ideas limit me more than they help. YMMV.
I just developed a small framework for this purpose.
You can check it out at: http://code.google.com/p/java-interceptor/ (use svn to check out).
There isn't a lot of magic in AspectJ. You can write your own agent. http://java.sun.com/javase/6/docs/api/java/lang/instrument/package-summary.html seems to be good starting point.
Why cannot your class implement an interface? You could just extract some interface from it containing all the methods that you want to intercept and use the dynamic proxies mechanism easily. It's also a good programming practice to code with interfaces and not classes.
You could use Spring framework with Spring AOP capabilities (which are using dynamic proxies inside) to do it. You will just have to define your class as a Spring bean in the configuration file and clients of your class will have to either get its instance from the Spring application context or as a dependency automatically (by defining the setMyClass(MyClass mc) method for instance). From there you can easily go to defining an aspect that intercepts all the method calls to this class.