I'm using Mockito with Junit version : 4.8.2
I'm not able to mock methods which expects any interface objects.
For example,
public interface If extends Xyz {
}
Class Abc {
protected List <String> getIPAddress(If x, String n) {
}
}
This is sample test method:
#Test
public void testGetIPAddress() {
Abc mockAbc = mock(Abc.class, CALLS_REAL_METHODS);
when(mockAbc.getIPAddress(any(Xyz.class), anyString())).thenReturn(new List <String>());
}
When I run the above method, I get:
NullPointerException
UPDATES
Actually I found out that the problem is using "CALLS_REAL_METHODS", when instantiating mocked object. Even if I use
when(mockAbc.getIPAddress(any(If.class), anyString())).thenReturn(null);
It is throwing NPE. The reason might be it's still calling the real method.
How do I override calling the real method in this case?
you need to call getIpAdress with an If not an Xyz
Also, new List <String>() won't work, as List is an interface, use new ArrayList<String>() instead:
#Test
public void testGetIPAddress() {
Abc mockAbc = mock(Abc.class, CALLS_REAL_METHODS);
when(mockAbc.getIPAddress(any(If.class), anyString())).thenReturn(new ArrayList<String>());
}
Related
I'm trying to override a private method on a Java class using meta programming. The code looks something like this:
// Java class
public class MyClass{
private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;
public void init(){
property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();
doSomethingCrazyExpensive();
}
private void doSomethingCrazyExpensive(){
System.out.println("I'm doing something crazy expensive");
}
}
// Groovy class
public class MyClassTest extends Specification{
def "MyClass instance gets initialised correctly"(){
given:
ExpandoMetaClass emc = new ExpandoMetaClass( MyClass, false )
emc.doSomethingCrazyExpensive = { println "Nothing to see here..." }
emc.initialize()
def proxy = new groovy.util.Proxy().wrap( new MyClass() )
proxy.setMetaClass( emc )
when:
proxy.init()
then:
proxy.property1 != null
proxy.property2 != null
}
}
The problem is that the overridden implementation of doSomethingCrazyExpensive isn't called - I think that this is because the private method is called by the init() method internally and not called through the metaClass. If I call myProxy.doSomethingCrazyExpensive() directly, the overridden method is invoked, so the meta-programming does work to some degree.
Is there a way to use meta programming to override a method on a Java class (or instance) in such a way that the overridden implementation is called when it is invoked internally?
Groovy as operator is quite powerful, and can create proxies out of concrete types whose changes are visible in Java. Sadly, seems like it can't override private methods, though i managed to change a public method:
Java class:
public class MyClass{
public void init(){
echo();
doSomethingCrazyExpensive();
}
public void echo() { System.out.println("echo"); }
private void doSomethingCrazyExpensive(){
System.out.println("I'm doing something crazy expensive");
}
}
Groovy test:
class MyClassTest extends GroovyTestCase {
void "test MyClass instance gets initialised correctly"(){
def mock = [
doSomethingCrazyExpensive: { println 'proxy crazy' },
echo: { println 'proxy echo' }
] as MyClass
mock.init()
mock.doSomethingCrazyExpensive()
}
}
It prints:
proxy echo
I'm doing something crazy expensive
proxy crazy
So the public method got intercepted and changed, even when being called from Java, but not the private one.
You cannot override a method called from Java code in Groovy using metaClass.
That's why you won't be able to "mock" the call to this private method in Java: it is being called by the Java class itself, not from Groovy.
This limitation wouldn't apply, of course, if your class was written in Groovy.
I would suggest that you refactor the Java class if you can so that you can use normal means to mock the expensive method call. Or even make the method protected, then override it in a sub-class.
I stumbled on this question and thought I should provide a different answer: Yes you can override an existing method - you just have to change the meta class to ExpandoMetaClass.
This happens automatically when you add your first method, for example.
Here's an example:
println ""
class Bob {
String name
String foo() { "foo" }
void print() { println "$name = ${foo()} ${fum()} metaclass=${Bob.metaClass}"}
def methodMissing(String name, args) { "[No method ${name}]" }
}
new Bob(name:"First ").print()
Bob.metaClass.fum = {-> "fum"}
new Bob(name:"Second").print()
Bob.metaClass.fum = {-> "fum"}
new Bob(name:"Third ").print()
Bob.metaClass.foo = {-> "Overriden Foo"}
new Bob(name:"Fourth").print()
The results are:
First = foo [No method fum] metaclass=org.codehaus.groovy.runtime.HandleMetaClass#642a7222[groovy.lang.MetaClassImpl#642a7222[class Bob]]
Second = foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
Third = foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
Fourth = Overriden Foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
You can see after the fum method was added the meta class changed to an expando. Now when the attempt is made to override the original foo - it works.
It seems you can't use Groovy metaprogramming to replace methods of Java classes - even public methods - try the following in the Groovy console to confirm:
ArrayList.metaClass.remove = { obj ->
throw new Exception('remove')
}
ArrayList.metaClass.remove2 = { obj ->
throw new Exception('remove2')
}
def a = new ArrayList()
a.add('it')
// returns true because the remove method defined by ArrayList is called,
// i.e. our attempt at replacing it above has no effect
assert a.remove('it')
// throws an Exception because ArrayList does not define a method named remove2,
// so the method we add above via the metaClass is invoked
a.remove2('it')
If you can modify the source code of MyClass, I would either make doSomethingCrazyExpensive protected, or preferably, refactor it so that it's more test-friendly
public class MyClass {
private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;
private CrazyExpensive crazyExpensive;
public MyClass(CrazyExpensive crazyExpensive) {
this.crazyExpensive = crazyExpensive;
}
public void init(){
property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();
crazyExpensive.doSomethingCrazyExpensive();
}
}
public interface CrazyExpensive {
public void doSomethingCrazyExpensive();
}
After making the changes above, when testing MyClass you can easily instantiate it with a mock/stub implementation of CrazyExpensive.
I have started learning JUNIT.
Here is what i am trying to achieve.
I have a class which checks if the inputString is part of secretKey;
public class StringChecker {
public boolean isEqual(String name)
{
boolean isEqual = false;
if(getSecretKey().contains(name))
{
isEqual = true;
}
return isEqual;
}
public String getSecretKey()
{
return "OSKAR";
}
}
My test class is this
public class RandomCheck {
#Test
public void isEqualTest()
{
StringChecker stringChecker = mock(StringChecker.class);
when(stringChecker.getSecretKey()).thenReturn("james");
//assertEquals(true, new StringChecker().isEqual("OSKAR")); <----this test case passes
assertEquals(true, stringChecker.isEqual("james"));
}
}
When i use Mocked object it does not give me the expected result, hence failing the test. But when i use a real object it gives me expected result and passes the test.
Am i missing anything? Like any annotation
A mockito mock is an object having the interface of the mocked class, but not its implementation. Your StringChecker is mocked, meaning there is no implementation code making calls from isEqual to getSecretKey as you assume.
You could use mockito spy, See this SO question:
Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.
ROOKIE MISTAKE
Here's the rookie mistake i did (mentioned by Arnold).
I mocked the StringChecker class but i did not provide any implementation for isEqual(String) method.
And because there was no implementation, i was getting the default value. In this case false (return type of method is boolean).
Solution
Using static method spy(). (Again mentioned by #Arnold).
So here is what my working code looks like.
#Test
public void isEqualTest()
{
StringChecker stringChecker = new StringChecker();
StringChecker spy = spy(stringChecker);
when(spy.getSecretKey()).thenReturn("james"); // providing implementation for the method
assertEquals(true, spy.isEqual("james"));
}
What i learnt from it.
Just by mocking an object does not get your things done if you intend to use methods of mocked object (In simple terms PROVIDE IMPLEMENTATION for methods of mocked objects).
TIP
If you want to see the default value returned by mocked object, just call the method of mocked object in sysout(without giving implementation).
Hope it will help someone like me.Peace
An alternative way without mocking and with additional test cases:
#Test
public void isEqualTest() {
StringChecker stringChecker = new StringChecker() {
#Override
public String getSecretKey() {
return "james";
}
};
assertTrue(stringChacker.isEqual("james"));
assertTrue(stringChacker.isEqual("jam"));
assertTrue(stringChacker.isEqual("mes"));
assertFalse(stringChacker.isEqual("oops"));
}
BTW, the isEqual() can be simplified to one line:
public boolean isEqual(String name) {
return getSecretKey().contains(name);
}
I am using Powermock to unit test a class.
The Class has a queue of List of objects as private member.
I am using PowerMock createPartialMock to partially mock two of the methods (say A and B) and then explicitly calling method C and then verify.
Class Sample {
Queue<List> q;
public C() {
A();
B();
q.add(List);
}
private A() {}
private B() {}
}
Class Test {
void testSomeMethod() {
Sample mock = PowerMock.createPartialMock(Sample.class, "A", "B");
PowerMock.expectPrivate(Sample.class, A).thenReturn("true");
PowerMock.expectPrivate(Sample.class, B).thenReturn("true");
mock.C();
PowerMock.verify(mock);
}
}
Now when I run the tests, PowerMock throws exception at q.add(List); line.
Can anyone please point out what mistake am I making?
Do I have expect q.add() method call as well?
You should somehow assign a value to q attribute of Sample class.
This can be done on constructor, by a setter method or by reflection (Whitebox class or pure Java reflection code).
If you need to check whether a item is added to q, create a mock of Queue interface.
I have created a method, in which i am using JaloSession. I am writing a Junit test for this.
Please let me know how can i mock the following.
ABC abc = JaloSession.getCurrentSession.getAttribute("abc");
Thanks in advance.
With powermock you can mock the static call:
mockStatic(JaloSession.class);
expect(JaloSession.getCurrentSession()).andReturn(yourMock);
...etc
However you don't need to do that. Perhaps the easiest thing since you control the code is to wrap this method call in a protected method
protected ABC getAbc(){
return JaloSession.getCurrentSession.getAttribute("abc");
}
And then in your tests, make a subclass of your class that overrides getAbc() to return a different ABC instance.
#Test
public void myTest(){
final ABC mockAbc = ....
Foo foo = new Foo(){
#Override
protected ABC getAbc(){
return mockAbc;
}
};
//do test on Foo
}
You can't (easily) because of the static call.
So either pass the current session in to the function you are testing, or define an interface for getting the current session and pass that to your object's constructor. In production implement it to call the static nmethod, and in test either mock it or build a fake.
As a bonus you will end up with a cleaner design, where dependencies are passed in from above instead of directly accessed at the lowest levels.
With the JMockit mocking library, you can mock it as follows:
#Test
public void mockJaloSession(#Mocked final JaloSession jalo) {
final ABC testABC = new ABC();
new Expectations() {{ jalo.getAttribute("abc"); result = testABC; }};
// From code under test:
ABC abc = JaloSession.getCurrentSession().getAttribute("abc");
assertSame(testABC, abc);
}
(The test doesn't need to worry about the getCurrentSession() call as it will automatically return the mock jalo object.)
I have a void method "functionVoid" that informs a parameter.
public class MyMotherClass {
#Inject
MyClass2 myClass2
public String motherFunction(){
....
String test = "";
myClass2.functionVoid(test);
if (test.equals("")) {
IllegalArgumentException ile = new IllegalArgumentException(
"Argument is not valid");
logger.throwing(ile);
throw ile;
}
....
}
}
public class MyClass2 {
public void functionVoid(String output_value)
{ ....
output_value = "test";
....
}
}
How do I mock this method in the JUnit method my method "motherFunction"?
In my example, the "test" variable is still empty.
#RunWith(MockitoJUnitRunner.class)
public class MyMotherClassTest {
#Mock
private MyClass2 myClass2 ;
#InjectMock
private final MyMotherClass myMotherClass = new MyMotherClass ();
#Test
public void test(){
myMotherClass.motherFunction();
}
}
If you want to mock the return result of motherFunction then you need not worry about the internal implementation of the method (which ends up calling functionVoid). What you do need to do is provide Mockito with an instruction as to what to do when the method, motherFunction is invoked, this can be achieved via the when clause with syntax;
when(mockedObject.motherFunction()).thenReturn("Any old string");
If that misses the point of what you are attempting to achieve then look at how to mock void methods in the documentation and determine whether the use of doAnswer is applicable here, something like;
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
String output_value = invocation.getArguments()[0];
output_value = "Not blank";
return null;
}
}).when(myClass2).functionVoid(anyString());
If you can change functionVoid() to accept a mutable object as the parameter, then you should be able to achieve what you want.
For example, if you change functionVoid() as follows:
public void functionVoid(StringBuilder output_value)
{ ....
output_value.append("test");
....
}
and invoke it in your motherFunction as follows:
public String motherFunction(){
....
StringBuilder test = new StringBuilder();
myClass2.functionVoid(test);
if (test.toString().equals("")) {
Now modifying OceanLife's answer above, you should be able to do the following:
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
StringBuilder output_value = invocation.getArguments()[0];
output_value.append("Not blank");
return null;
}
}).when(myClass2).functionVoid(any(StringBuilder.class));
Of course, if you can change functionVoid(), you could also just make it return a String instead of void.
In my example, the "test" variable is still empty.
This is not a Mockito problem.
Take a look at this question and especially this answer.
The gist of it is that Java is pass by value (this is explained far better at the links above). Nothing in Mockito or Java will ever be able to make the test var anything other than an empty String. It's an empty String before the method call, and will be an empty String after the call.
You can change an object's state within a method (e.g. adding objects to a collection within a method) and see those changes when you exit the method, but you cannot change what object a var references within a method and expect those changes to "stick" once you exit the method. Strings however, are effectively immutable (no state to change), so you can't even do this.
Thus no modifications to test can be made within that method call.
If you want to check method someMethod(String arg) of object Obj then:
String argument = "";
Mockito.verify(Obj, Mockito.times(1)).someMethod(argument);
Obj has to be Mock or Spy.
This works when you want to check if proper argument was passed to void method.
If your method modifies somehow argument then you should use assertion:
someMethod(StringWrapper wrapper) that changes string.
// given
String argument = "a";
String expected = "a_changed";
String wrapped = new StringWrapper(a);
// when
someMethod(wrapped);
// then
Assert.assertEquals(wrapped.getString(), expected)
I am not sure if this what you were looking for?