How to augment methods during ByteBuddy transformation? - java

Context
I am implementing byte code transformations with ByteBuddy and the process of manipulation is a multi step process.
Because of that, the manipulation has to be able to:
augment originally existing methods
create new methods entirely
augment a method that was introduced via 2.
For 1. I used an #OnMethodExit advice applied via:
Builder<?> builder = builder.visit(Advice.to(Helper.class)
.on(ElementMatchers.hasMethodNamed(name));
with Helper the augmentation code for the method (effectively setting a field's value).
When creating new methods, I build them as follows:
Builder<?> builder = builder.defineMethod(…)
.intercept(MethodDelegation.to(OtherHelper.class));
.…;
OtherHelper consumes the runtime instance via a static method taking #This Object object as argument.
The problem
In short: I don't see the former transformation applied if it follows the latter.
The actual execution order is as follows:
My type gets processed and a method added via MethodDelegation.….
In a subsequent step I find that newly introduced method and try to augment the implementation generation through Advice.to(…) using an #OnMethodExit advice.
The resulting code has the behavior of step 1 but is lacking the behavior of step 2.
I am assuming I invalidly combine the two parts of the implementation. Any ideas? A hunch: does the ElementMatcher matching the augmentation by name not see the method introduced using ….defineMethod(…) yet? The name is coming from some method inspection I start from builder.toTypeDescription() which actually makes me assume that the to-be-created method is already visible to the builder as otherwise it wouldn't be found in that step in the first place.

Can you share a reconstruction of your example? In a simple example, I observe the expected behavior:
public class Bar {
public static void main(String[] args) throws Exception {
Class<?> type = new ByteBuddy().subclass(Object.class)
.visit(Advice.to(Bar.class).on(named("m")))
.defineMethod("m", void.class, Visibility.PUBLIC)
.intercept(MethodDelegation.to(Bar.class))
.make()
.load(Bar.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
type.getMethod("m").invoke(type.getConstructor().newInstance());
}
#BindingPriority(2)
public static void delegation() {
System.out.println("Delegation!");
}
#Advice.OnMethodEnter
public static void enter() {
System.out.println("Advice!");
}
}
This example prints both Advice! and Delegation!.

Related

How can I create fake data and the data object for unit testing?

I have a class that implements a cache and I want to write a JUnit test for it.
The class implements and interface with methods like:
public void insert(Object key, Object value);
public Object getFromCache(Object key);
and the basic implementation is a singleton.
I am writing a JUnit test but I don't know how to properly create a dummy cache with data in order to use for testing.
Right now I am doing:
#Test
public void myTest() {
MyCache cache = MyCache.getInstance();
populateWithData(cache);
//test cache
asserEquals etc
}
How can I avoid using the getInstance() and not populate on each test?
Apparently I slightly misread your question.
As the other two answers state, if you want to have a specific cache which you can read from when running each testcase, you could use a ´#before´ method, which initializes your object to be used in your testcase. Each ´#before´ method defined is called prior to calling each testcase. This means that you can write the code to instantiate the object once instead of many times.
Note that if you want to do something different in a testcase, consider adding the customization at the top of that, instead of edition your #before method, since that will impact all your testcases.
Just for clarity's sake, I will include some code:
MyCache cache = null;
#before
public void initCache(){
cache = MyCache.getInstance();
populateWithData(cache);
}
// ... rest of your program here ...
Original answer:
You can use this if you want to do more fancy testing of more complicated objects. This can still be used in conjunction with the ´#before´ annotation
You could try mockito...
This is basically a framework to mock off a function or class, that you are not interested in implementing in its totally, especially for testing.
Here is a sample using a mocked off list:
import static org.mockito.Mockito.*;
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
// you can mock concrete classes, not only interfaces
LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");
// the following prints "first"
System.out.println(mockedList.get(0));
// the following prints "null" because get(999) was not stubbed
System.out.println(mockedList.get(999));
You can basically tell mockito which functions you expect to call on the object, and what you expect the result to be... very versatile. I expect that it will fulfill your needs.
'Reset' singleton before each test. More details can be found here.
For example:
#Before
public void resetMyCacheSingleton() throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
Field instance = MyCache.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, null);
}
You can use #BeforeClass annotation to do something which will be common and may be computational expensive stuff.
This will ran only once before all the testcases.
#BeforeClass
public static void myTest() {
MyCache cache = MyCache.getInstance();
populateWithData(cache);
//test cache
asserEquals etc
}
P.S. Since #BeforeClass can be used with static method only, populateWithData() needs to be static as well. and since populateWithData() method is static, variables used inside it must be static as well.
You can also check #AfterClass to clean/reset some data/resources.

Is it possible to use JMockit's Deencapsulation API to exchange method implementation?

So, basically, a there is some poor code that I cannot change that needs to be tested. Traditionally, you inject your mocked dependencies, but with this code, I cannot do so, because there are no setter methods. Worse, the function I need to test calls a bunch of static factory methods-I can't just use the MockUp strategy to swap out the implementation there, because there is no class instance to be injected at all.
In C/++, you can retrieve a pointer to a function and know it's type by it's signature. If you changed the pointer, then you could potentially change how the stack was constructed by the compiler and you could pass function's around and all that Jazz.
Is there a way to use the Deencapsulation API to replace a static method implementation? Using this, I could write my own class, descend from the traditional, but return mocked objects in order that dependency injection still be achieved?
public class TestedClass {
public static void testedMethod() {
UnMockableType instanceVariable =
UnInjectableFactory.staticFactoryConstructor();
instanceVariable.preventControlFlowInfluenceThroughMocking();
}
}
Easy enough:
#Test
public void exampleTestUsingAMockUp()
{
new MockUp<UnMockableType>() {
#Mock
void preventControlFlowInfluenceThroughMocking() {}
};
TestedClass.testedMethod();
}
Above, UnInjectableFactory isn't mocked because it doesn't need to be (assuming it simply instantiates/recovers an UnMockableType).
It could also be done with #Mocked and the Expectations API.

How can I create linked invocations on my object in Java to execute a set of instructions by chaining methods together?

I'm learning Java and want to implement method chaining to build a set of execution instructions. I've heard about some design patterns like builder or command pattern (I don't know what those patterns are btw, just heard their names floating around in my learning journey). But not sure if I would be complicating things if I chose to go with a OOP design pattern.
So this is what I want to build:
Hypothetically speaking, lets say I have a class in my program called DatabaseOperator.
In terms of design, I would I go about designing the class so that the client that uses DatabaseOperator could use it like shown below:
public static void main(String args[]){
DatabaseOperator do = new DatabaseOperator();
DatabaseOperator.getConfigurations("fileName").getAuthenticationDetails("somefile").
joinCluster("clusterName").launchMode("TEST").initiateConnection();
}
How should I design my DatabaseOperator class? Any particular design pattern I can use or is it not needed?
Thank you in advance.
You could design your DatabaseOperator class to support chained invocations, by returning the this object in the different methods. Each of these methods will update the state of the DatabaseOperator in order to facilitate proper execution of other methods (such as initiateConnection()) down the line.
As Jordao pointed out, this looks more like a Fluent Interface (that uses a Builder pattern under the hood). One possible implementation could be:
public class DatabaseOperator {
private Configuration configuration = Configuration.DEFAULT;
private AuthDetails authDetails = AuthDetails.DEFAULT;
public DatabaseOperator withConfigurationsFrom(String fileName) {
//Get the configurations from the file, and initialize the 'Configuration' object
configuration = initializeFrom(fileName);
return this;
}
public DatabaseOperator withAuthenticationDetailsFrom(String fileName) {
// Get authentication details from the file, and initialize AuthenticationDetails
authDetails = initializeAuthDetailsFrom(fileName);
return this;
}
//.. and so on
public void initiateConnection() {
//Uses configuration and authDetails
}
}

Mockito: Trying to spy on method is calling the original method

I'm using Mockito 1.9.0. I want mock the behaviour for a single method of a class in a JUnit test, so I have
final MyClass myClassSpy = Mockito.spy(myInstance);
Mockito.when(myClassSpy.method1()).thenReturn(myResults);
The problem is, in the second line, myClassSpy.method1() is actually getting called, resulting in an exception. The only reason I'm using mocks is so that later, whenever myClassSpy.method1() is called, the real method won't be called and the myResults object will be returned.
MyClass is an interface and myInstance is an implementation of that, if that matters.
What do I need to do to correct this spying behaviour?
Let me quote the official documentation:
Important gotcha on spying real objects!
Sometimes it's impossible to use when(Object) for stubbing spies. Example:
List list = new LinkedList();
List spy = spy(list);
// Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
when(spy.get(0)).thenReturn("foo");
// You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
In your case it goes something like:
doReturn(resultsIWant).when(myClassSpy).method1();
In my case, using Mockito 2.0, I had to change all the any() parameters to nullable() in order to stub the real call.
My case was different from the accepted answer. I was trying to mock a package-private method for an instance that did not live in that package
package common;
public class Animal {
void packageProtected();
}
package instances;
class Dog extends Animal { }
and the test classes
package common;
public abstract class AnimalTest<T extends Animal> {
#Before
setup(){
doNothing().when(getInstance()).packageProtected();
}
abstract T getInstance();
}
package instances;
class DogTest extends AnimalTest<Dog> {
Dog getInstance(){
return spy(new Dog());
}
#Test
public void myTest(){}
}
The compilation is correct, but when it tries to setup the test, it invokes the real method instead.
Declaring the method protected or public fixes the issue, tho it's not a clean solution.
The answer by Tomasz Nurkiewicz appears not to tell the whole story!
NB Mockito version: 1.10.19.
I am very much a Mockito newb, so can't explain the following behaviour: if there's an expert out there who can improve this answer, please feel free.
The method in question here, getContentStringValue, is NOT final and NOT static.
This line does call the original method getContentStringValue:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), isA( ScoreDoc.class ));
This line does not call the original method getContentStringValue:
doReturn( "dummy" ).when( im ).getContentStringValue( anyInt(), any( ScoreDoc.class ));
For reasons which I can't answer, using isA() causes the intended (?) "do not call method" behaviour of doReturn to fail.
Let's look at the method signatures involved here: they are both static methods of Matchers. Both are said by the Javadoc to return null, which is a little difficult to get your head around in itself. Presumably the Class object passed as the parameter is examined but the result either never calculated or discarded. Given that null can stand for any class and that you are hoping for the mocked method not to be called, couldn't the signatures of isA( ... ) and any( ... ) just return null rather than a generic parameter* <T>?
Anyway:
public static <T> T isA(java.lang.Class<T> clazz)
public static <T> T any(java.lang.Class<T> clazz)
The API documentation does not give any clue about this. It also seems to say the need for such "do not call method" behaviour is "very rare". Personally I use this technique all the time: typically I find that mocking involves a few lines which "set the scene" ... followed by calling a method which then "plays out" the scene in the mock context which you have staged... and while you are setting up the scenery and the props the last thing you want is for the actors to enter stage left and start acting their hearts out...
But this is way beyond my pay grade... I invite explanations from any passing Mockito high priests...
* is "generic parameter" the right term?
One more possible scenario which may causing issues with spies is when you're testing spring beans (with spring test framework) or some other framework that is proxing your objects during test.
Example
#Autowired
private MonitoringDocumentsRepository repository
void test(){
repository = Mockito.spy(repository)
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
In above code both Spring and Mockito will try to proxy your MonitoringDocumentsRepository object, but Spring will be first, which will cause real call of findMonitoringDocuments method. If we debug our code just after putting a spy on repository object it will look like this inside debugger:
repository = MonitoringDocumentsRepository$$EnhancerBySpringCGLIB$$MockitoMock$
#SpyBean to the rescue
If instead #Autowired annotation we use #SpyBean annotation, we will solve above problem, the SpyBean annotation will also inject repository object but it will be firstly proxied by Mockito and will look like this inside debugger
repository = MonitoringDocumentsRepository$$MockitoMock$$EnhancerBySpringCGLIB$
and here is the code:
#SpyBean
private MonitoringDocumentsRepository repository
void test(){
Mockito.doReturn(docs1, docs2)
.when(repository).findMonitoringDocuments(Mockito.nullable(MonitoringDocumentSearchRequest.class));
}
Important gotcha on spying real objects
When stubbing a method using spies , please use doReturn() family of methods.
when(Object) would result in calling the actual method that can throw exceptions.
List spy = spy(new LinkedList());
//Incorrect , spy.get() will throw IndexOutOfBoundsException
when(spy.get(0)).thenReturn("foo");
//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
I've found yet another reason for spy to call the original method.
Someone had the idea to mock a final class, and found about MockMaker:
As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line: mock-maker-inline
Source: https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
After I merged and brought that file to my machine, my tests failed.
I just had to remove the line (or the file), and spy() worked.
One way to make sure a method from a class is not called is to override the method with a dummy.
WebFormCreatorActivity activity = spy(new WebFormCreatorActivity(clientFactory) {//spy(new WebFormCreatorActivity(clientFactory));
#Override
public void select(TreeItem i) {
log.debug("SELECT");
};
});
As mentioned in some of the comments, my method was "static" (though being called on by an instance of the class)
public class A {
static void myMethod() {...}
}
A instance = spy(new A());
verify(instance).myMethod(); // still calls the original method because it's static
Work around was make an instance method or upgrade Mockito to a newer version with some config: https://stackoverflow.com/a/62860455/32453
Bit late to the party but above solutions did not work for me , so sharing my 0.02$
Mokcito version: 1.10.19
MyClass.java
private int handleAction(List<String> argList, String action)
Test.java
MyClass spy = PowerMockito.spy(new MyClass());
Following did NOT work for me (actual method was being called):
1.
doReturn(0).when(spy , "handleAction", ListUtils.EMPTY_LIST, new String());
2.
doReturn(0).when(spy , "handleAction", any(), anyString());
3.
doReturn(0).when(spy , "handleAction", null, null);
Following WORKED:
doReturn(0).when(spy , "handleAction", any(List.class), anyString());

Controlling when object is created

Suppose i need to create an object as follows and set some values
FileMetaData fileMeta = fileContainer.getMetaData();
fileMeta.setFileName("file name");
fileMeta.setServer("my box");
fileMeta.setDirectory("/path/to/dir");
fileMeta.setFileType(FileType.PROPERTIES);
I later intend to use this object reference to do something useful.
I'd like to recognize the fact that it is possible for the user of the system to not set some fields, for instance, one may forget to
fileMeta.setDateModified(12345);
Is it somehow possible to guarantee that all (or some specific) fields are set before making the object available?
There is nothing in the language to enforce this (except for having a lone visible constructor that takes all the required parameters), but you can do it idiomatically, with a variation on the builder pattern and some method chaining:
FileMetaData fileMeta = new FileMetaDataBuilder(fileContainer.getMetaData())
.setFileName("file name")
.setServer("my box")
.setDirectory("/path/to/dir")
.setFileType(FileType.PROPERTIES)
.build();
The build() method can ensure that all the required fields are set before calling the appropriate constructor of FileMetaData with all the required parameters.
Use the builder pattern and pass the reference to the builder around. When you're done adding extras on top, call .build and capture the returned instance of FileMetaData.
You could constrain it by not allowing the build to succeed until all of the pre-requisites are set.
Basically I can classify the following 3 ways.
First is based on the class itself. You can add method isReady() to your class. This method will perform all checks and return true or false.
Other way is to use Factory or Builder pattern and probably objects repository. Both factory and builder guarantee to create object in ready state. Repository can be used to "publish" ready objects there, so other code requests objects and receives them in ready state only.
Other approach is to use Wrapper (Decorator) pattern.
interface Foo {
public void foo(); //business method
}
class FooImpl implements Foo {
public void foo(){} // does the work
}
class FooDecorator implmeents Foo {
Foo foo;
public void foo(){
if (isInitialized()) {
foo.foo();
}
throw IllegalStateException("Not initialized");
}
}
This solutions may be implemented using dynamic proxy or using AOP framework as well.

Categories

Resources