I am a Software Engineer in Test, and I am trying to write code that can replace production side method so that test can execute those instead. Basically, I do not want to modify production code for testability.
Here is a simple scenario:
public class Foo {
public static void foo() {
printA();
}
public static void printA() {
System.out.println("A");
}
public static void printB() {
System.out.println("B");
}
}
public class Foobar {
public Foobar() {
}
public void test() {
Foo.foo();
}
public static void main(String[] args) {
//Try changing the method here
new Foobar().test();
}
}
As you can see, when the main executes, it will print "A" since it calls the method printA on static method foo(). Now on runtime, is there a way I can inject or modify such that foo will call printB instead of printA?
Thank you for all the help!
Look at AspectJ.
It provides advices, which can be used to execute some code around a method (before and after its execution), including bypassing the call to original method altogether and returning some arbirary value
If you're just doing this for testing out classes, you could use a mocking framework to mock the classes on the server. I like Mockito.
You can do it yourself using the java reflection api, or you can you use a tool like PowerMock.
Related
So I'm using MockedStatic<> to mock a static method but it seems like the item inside is still getting called? If this is the case, what's the point of mocking it? I have the following setup:
Object being tested:
public class ObjectBeingTested {
public void methodBeingTested() {
Object obj = ObjectInQuestion.getInstance(new Object(), "abc");
// do stuff with obj
}
}
The object with static method:
public class ObjectInQuestion {
public static ObjectInQuestion getInstance(Object obj, String blah) {
someLocalVar = new FileRequiredObject();
// we get NullPointerException here cuz in test env, no files found
}
private ObjectInQuestion() {
// private constructor to make people use getInstance
}
}
Test code:
public class MyTestClass {
MockedStatic<SomeClass> mySomeClass;
#Mock ObjectInQuestion mMockedObjectInQuestion;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mySomeClass = mockStatic(SomeClass.class);
when(SomeClass.getInstance(any(), anyString()).thenReturn(mMockedObjectInQuestion);
}
#After
public void tearDown() {
mySomeClass.close();
}
}
My questions are the following:
Why calling ObjectInQuestion.getInstance() in the test class, it's totally fine but when it's being called from ObjectBeingTested, it runs the real construction?
I tried to use mockConstruction on FileRequiredObject, it still actually construct the object ... why?
You're using the wrong syntax for stubbing the static method. You want something like
mySomeClass.when(
()->SomeClass.getInstance(any(), anyString()))
.thenReturn(mMockedObjectInQuestion);
More information available here
Assuming MockedStatic<SomeClass> mySomeClass; is actually MockedStatic<ObjectInQuestion> mySomeClass;, I would try to simplify the setup using a classic try block.
In any case, sharing the actual test method might be able to shine some light. ;)
I have a class which looks like below
public class HelloWorld{
public void sayHelloWorld(){
System.out.println("Hello World");
}
}
Now I would like to add another method to the HelloWorld class using bytebuddy and add a call to the new method in sayHelloWorld. So hypothetically the class would look like this after bytebuddy does it's magic. (I know that bytebuddy works with bytecode and not java source files. The below code is just for illustration purpose.)
public class HelloWorld{
public void sayHelloWorld(){
System.out.println("Hello World");
sayHelloAgain()
}
public void sayHelloAgain(){
System.out.println("Hello Again")
}
}
Firstly, is this possible with bytebuddy?
Secondly, if it is possible, how can I do it? I have understood that bytebuddy can be used to redefine methods, but not modify the method body. Is this true?
It would be great if someone could shed some light on this. TIA!
Byte Buddy allows you to do this in various ways. The most straight forward way would be to define an interceptor that implements sayHelloAgain to which Byte Buddy creates a delegation:
public class HelloAgainDelegate {
public static void sayHelloAgain() {
System.out.println("Hello again");
}
}
You can then define the method on the redefined class and rebase the sayHelloWorld method to first invoke the original method and then invoke the other method:
Class<?> type = new ByteBuddy()
.rebase(HelloWorld.class)
.defineMethod("sayHelloAgain", void.class, Visibility.PUBLIC)
.intercept(MethodDelegation.to(HelloAgainDelegate.class))
.method(named("sayHelloWorld"))
.intercept(SuperMethodCall.INSTANCE
.andThen(MethodCall.invoke(named("sayHelloAgain"))))
.make()
.load(HelloWorld.class.getClassLoader(),
ClassLoadingStrategy.Default.CHILD_FIRST)
.getLoaded();
Object instance = type.newInstance();
type.getMethod("sayHelloWorld").invoke(instance);
type.getMethod("sayHelloAgain").invoke(instance);
In Java code, the rebased class would look something like this:
public class HelloWorld {
synthetic void sayHelloWorld$origin() {
System.out.println("Hello World");
}
public void sayHelloWorld() {
sayHelloWorld$origin();
sayHelloAgain();
}
public void sayHelloAgain() {
HelloAgainInterceptor.sayHelloAgain();
}
}
If this delegation is not an option for you, you can also use Advice to inline the code from a template class:
class HelloAgainAdvice {
#Advice.OnMethodExit
static void sayHelloAgain() {
System.out.println("Hello again");
}
}
Instead of the MethodDelegation, you would use this class via Advice.to(HelloAgainAdvice.class). As the code is copied, you will not be able to set break points but your redefined class will be self-contained.
I've been trying to figure out stubbing and mocking through the groovy testing tutorial to no avail. I'm trying to stub (or mock, I'm not quite sure on the terminology) this method, however I can't figure out how to actually get the syntax right. I would appreciate some help. I'm using groovy 2.4.5
public class foo {
public static void main(String[] args){
method1();
}
public static void method1(){
//do stuff
Object baz = new Object();
method2(baz);
}
public static void method2(Object baz){
//do stuff
}
}
class FooTest extends groovy.util.GroovyTestCase {
void testMainLoop(){
def stubMethod2 = new StubFor(foo);
stubMethod2.ignore.method2
stubMethod2.use {
foo.method1();
}
}
}
This code throws the error:
groovy.lang.MissingPropertyException: No such property: method2 for class: groovy.mock.interceptor.Ignore
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:87)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
at fooTest.testMainLoop(fooTest.groovy:14)
You should rather use:
stubMethod2.ignore('method2')
than:
stubMethod2.ignore.method2
Could you please clarify what you want to achieve?
BTW: I suggest to use spock instead of groovy built-in testing.
I have a problem with a class that I am testing where in almost every method I want to test, one of the first things each method does is call this one specific method. This method that is called once by all of these other methods takes a long time to execute. I don't want to have to wait for this every time I run my tests, it really is just a huge waste of time.
I attempted to #Spy the method using Mocktio, but I ran into problems because the really long method doesn't return anything. Can someone suggest a good way to mock out a single method inside a class I am trying to test?
Example:
public class myClass {
public void methodOne() {
reallyLongMethod();
// More code
}
public void methodTwo() {
reallyLongMethod();
// More code
}
.
.
.
public void methodN() {
reallyLongMethod();
// More code
}
public void reallyLongMethod() {
}
}
This is the class I am trying to test. I want to test all of the 'methodX()' methods. I don't want to run reallyLongMethod everysingle time however.
So, is there a way to use Mockito 'Spy' to stub out reallyLongMethod()? Even though it doesn'treturn anything?
You can use a Spy with doNothing(), but make sure you use the spy during the test. Mockito spies copy the original, instead of delegating to it.
#RunWith(MockitoJUnitRunner.class)
public class YourTest {
// Option 1:
// #Spy MyClass myClass = new MyClass();
// Option 2 (see #Before method)
MyClass myClass;
#Before public void ignoreReallyLongMethod() {
myClass = spy(new MyClass()); // discard original
doNothing().when(myClass).reallyLongMethod();
}
#Test public void methodOneWorks() {
myClass.methodOne(); // you're using the spy here
assertEquals(42, myClass.getFoo());
}
}
Though this does evoke a code smell, don't mock or stub the class under test, as long as you're careful to test the method behavior (methodOne) and not the stubbed behavior (reallyLongMethod) you'll be good to go. If you do want to test reallyLongMethod you'll want to use a different object instance or else you'll "test" the doNothing() call alone. Do bear in mind that if reallyLongMethod and your other methods have any negative interactions, these tests won't tell you about that.
By the way, you can also do the equivalent without using Mockito, which may make a little clearer what you are or aren't doing with your mocks:
#RunWith(JUnit4.class)
public class YourTest {
MyClass myClass;
#Before public void createMyClass() {
myClass = new MyClass() { // create an anonymous inner class
#Override public void reallyLongMethod() {} // that does nothing here
};
}
}
I use Mockito 1.8.0 so I do not have AnyVararg. Upgrading to later version of Mockito is not on cards from my team at the moment. So please bear with me.
What the class looks like:
public abstract class Parent {
public void someMethod(String a, String b)
{
//.....
}
public void foo(String a, String... b)
{
//.....
}
}
public class Child extends Parent{
public void bar() {
someMethod(a,b);
foo(a,b,c);
methodToFailUsingSpy();
}
}
Unit tests
#Test
public void someTest() {
private spyOfChild = //initialize here;
doReturn("Something")).when(spyOfChild).methodToFailUsingSpy();
/* Tried using this, but did not help.
doCallRealMethod().when(spyOfChild).foo(anyString());
*/
spyOfChild.bar();
}
Problem -
When the spy sees someMethod(), it calls the real method in the abstract class. But when it sees foo(), it tries to find a matching stubbed method i.e control goes to Mockito's MethodInterceptorFilter, since it is not able to find a mock, it throws java.lang.reflect.InvocationTargetException.
I do not want foo() to be mocked. I want the real method to be called like it happens in someMethod(). Can someone explain if it is because of using method with variable length arguments with a spy?
This is a bug in Mockito.
https://groups.google.com/forum/#!msg/mockito/P_xO5yhoXMY/FBeS4Nf4X9AJ
Your example is quite complicated, to reproduce the problem is very simple:
class SimpleClass {
public String varargsMethod(String... in) {
return null;
}
public void testSpyVarargs() {
SimpleClass sc = Mockito.spy(new SimpleClass());
sc.varargsMethod("a", "b");
}
}
Even this will produce the error you describe, and the workaround suggested in the link doesn't work for me.
Unfortunately to get around this you will need to upgrade Mockito. Changing to version 1.9.5 makes the above run fine, plus you get the varargs matchers as you say (although note that your problem isn't to do with matchers but how Mockito handles spied varargs methods).
I don't think there were too many huge changes between 1.8.0 and 1.9.5, it shouldn't be too painful.