Get method invocated inside a method in Java - java

I want to make a JUnit test to assure that some classes don't use a specific set of methods (from another classes). Example
class MyClass
{
void myMethod()
{
otherClass.otherClassStaticMethod();
}
}
class myTest
{
void test()
{
assertFalse(CalledMethods.getMethodsCalledBy("myClass.myMethod").Contains("otherClass.otherClassStaticMethod"));
}
}
In this test I want to assure that myMethod doesn't invocate otherClassStaticMethod. How can I find what methods are being called inside a method in compile time (ignore methods called using reflection)? I thought about a .java parser, do you recommend any?

you can mock "otherClass" and verify that the method isn't invoked. E.g. using Mockito you can even specify in which order what methods are supposed to be invoked (under the condition their instances are mocks) and specify which methods are not allowed to be invoked
as coding.mof said, to mock static methods you should use PowerMock/PowerMockito:
example:
PowerMockito.mockStatic(OtherClass.class);
PowerMockito.verifyStatic(never());
OtherClass.otherClassStaticMethod();

It sounds like you should be using a mock library and let that handle it all for you. I'd recommend JMock as my library of choice. If you're using instance methods then this would be perfect for you - if, as your example shows, it's static methods then PowerMock may work*1.
With JMock, you'd have something like:
public class MyClass {
public MyClass(Dependency dependency) {
this.dependency = dependency;
}
void myMethod() {
dependency.someMethod();
}
}
#RunWith(JMock.class)
public class MyTest {
private Mockery context = new Mockery();
#Test
public void doesNotCallSomeMethod() {
Dependency dependency = context.mock(Dependency.class);
MyClass obj = new MyClass(dependency);
obj.myMethod(); <--- this will fail fast
}
}
When you call obj.myMethod, JMock will instantly report that you never said dependency should have any methods called. It will also tell you what method you DID call and what parameters you passed in if any
*1 I don't use PowerMock as I steer away from static methods unless they are pure functions

Related

How do I mock invocations to methods in super class using jMockit

I have a scenario in which I have to mock a method in parent class. The method is invoked from the method under test. I have not been able to mock the function using jMockit.
My super class is method is as follows
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
// Email recipients code. I want to mock this function.
}
}
My subclass is as follows
public class MyClass extends SuperClass {
public void methodUnderTest(HttpServletRequest request) {
// Some code here.
List<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
I have tried using partial mocks using jMockit's tutorial, but it has not worked for me. My test method is given below.
UPDATE: I implemented Rogerio's suggestion as follows. The implementation still calls the real method. When I debug the instance of mocked class in Eclipse, this is what I see com.project.web.mvc.$Subclass_superClass#6b38c54e
#Test
public void testMethodUnderTest(#Mocked final SuperClass superClass) throws Exception {
final MyClass myClass = new MyClass();
new Expectations(myClass) {{
// .. Other expectations here
superClass.emailRecipients((List<String>) any);
}};
MockHttpServletRequest req = new MockHttpServletRequest();
myClass.methodUnderTest(req);
}
The issue is that when I try to mock the invocation of emailRecipients, it always tries to call the actual function. I am using Java 7, jMockit v1.35, and Maven 3x for our builds.
UPDATE The code is legacy code. As a result, we can't update it. We can not use PowerMock as it is not among the libraries that have been approved by the company. We can use either jMockit or Mockito or a combination of both.
The fact that you want to mock the method from parent class shows that your approach fails the Separation of Concerns/Single responsibility Pattern (SoC/SRP).
The use of PowerMock as suggested by Rajiv Kapoor is possible but this (as any use of PowerMock) would be a surrender to bad design.
You can solve your design problem by applying the Favor Composition over Inheritance principle (FCoI).
To do so you'd change your (most likely) abstract super class into a "normal" class. You'd create an interface that declares all the public and abstract methods in your super class. Your child class would no longer extend the parent class but implement the interface. It would get an instance of the former parent class as dependency and call it's methods providing common behavior as needed.
This dependency can easily mocked without the need of PowerMock.
UPDATE The code is legacy code. As a result, we can't update it.
In that case you are outruled.
The code you have is not unittestable because it is written in an untestable way. Your only chance is to write module and/or acceptance tests (without the use of a mocking framework) covering each and every execution path through your code.
This test will be expensive to create and slow but they will gurad your when refactoring the code to something testable (== changable) later.
see below example
P.S. use Mockito.any(HttpServletRequest.class)instead of Mockito.any(ArrayList.class) for your code
Super Class
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
System.out.println("Emailed!");
}
}
MyClass
public class MyClass extends SuperClass {
public void methodUnderTest() {
// Some code here.
ArrayList<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
Test Class
public class TestCase {
MyClass myClass = Mockito.mock(MyClass.class, Mockito.CALLS_REAL_METHODS);
#Before
public void prepare() {
PowerMockito.doNothing().when(myClass).emailRecipients(Mockito.any(ArrayList.class));
/*PowerMockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
System.out.println("Custom code");
return null;
}
}).when(myClass).emailRecipients(Mockito.any(ArrayList.class));*/
}
#Test
public void testMethodUnderTest() throws Exception {
myClass.methodUnderTest();
}
}
If you don't want the code in emailRecipients to execute then use doNothing()
else use doAnswer to execute some other code

JUnits for constructors which uses third party API call

Below mentioned is the class that I need to test:
public class MyClass {
private String key;
public MyClass(Connection con) {
key = ThirdPartyApi.getkey(con);
}
public String getKey() {
return key;
}
}
Now I need to test this constructor, but am unable to mock this Third party API call. And the Test case would be as mentioned below :
public class MyClassTest{
#Test
public void test1(){
MyClass c = new MyClass(dummyconnection);
assertNotNull(c.getKey != null);
}
}
But this case would be giving me an error that ThirdPartyAPI Class is failing as the the connection object is mocked.
So I want to mock this ThirdPartyApi call. Is it possible using Easymock, powermock?
Simple: EasyMock does not support mocking static calls. So you can turn to PowerMock(ito) or JMockit in case you do not want to change your code.
But the better approach would be to understand that using static always leads to tight coupling between your classes, and that you want to make sure that this doesn't affect your ability to unit test your code.
In your case:
public MyClass(Connection con) {
key = ThirdPartyApi.getkey(con);
simply replace that with:
public MyClass(Connection con) {
this (ThirdPartyApi.getkey(con));
}
/** unit testing only */
MyClass(Key key) {
...
And voila, you got a constructor that you can call from your unit test - and now you simply pass a mocked key object. And your tests will no longer execute that static call - because you use the key-taking constructor in all your tests.
But you probably want another test case to make sure that calling the public constructor does what you expect it to do - and that could be to throw an exception because that static call fails.
Beyond that: I fully agree with the comments - the fact that your constructor is doing so much (including static calls) has a certain design smell on it.

How to mock an object created via Class.newInstance(className)?

I'm trying to add unit tests to some legacy code that has a String class name passed to it and that creates an object implementing a particular handler interface using Class.newInstance(String className). I can control the class name I'm passing, I can get a pointer to the new handler object (via a getHandler() call), and I would like to observe calls to it using Mockito.
My current solution is:
Create a new test class TestHandler that implements the interface.
Have that test class contain a Mockito mock object that also implements the interface.
Manually pass through all the interface methods to the mock object.
Make the mock object accessible via a getMock() method.
Observe the object by making verify() calls to objectUnderTest.getHandler().getMock().
This works, but feels a little inelegant, especially having to manually write all the pass-thru methods.
Is there a better solution?
Fundamentally, you're running into the same problems as trying to test a newly-created instance using new; the Class.newInstance (probably properly Class.forName(foo).newInstance()) doesn't hurt you, but doesn't help you either.
As a side note, your TestHandler sounds like a general purpose delegate implementation, which sounds pretty useful anyway (particularly if you ever need to write a Handler wrapper). If it is, you might want to promote it to be adjacent to your Handler in your production code tree.
Though I recognize that you mention legacy code, this becomes very easy if you are allowed to refactor to include a testing seam. (Ignoring reflective exceptions here for ease of explanation.)
public ReturnType yourMethodUnderTest(String className) {
return yourMethodUnderTest(Class.newInstance(className));
}
/** Package private for testing. */
public ReturnType yourMethodUnderTest(Handler handler) {
return yourMethodUnderTest(Class.newInstance(className));
}
You could also extract the object creation and replace it in your test:
/** Instance field, package-private to replace in tests. */
Function<String, Handler> instanceCreator =
( x -> (Handler) Class.forName(x).newInstance());
public ReturnType yourMethodUnderTest(String className) {
Handler handler = instanceCreator.apply(className);
// ...
}
You could even just extract it to a method and replace it in your test:
public ReturnType yourMethodUnderTest(String className) {
Handler handler = createHandler(className);
// ...
}
/** Package private for testing. */
Handler createHandler(String className) {
return Class.forName(className).newInstance();
}
#Test public void yourTest() {
// Manually replace createHandler. You could also use a Mockito spy here.
ObjectUnderTest objectUnderTest = new ObjectUnderTest() {
#Override Handler createHandler(String className) {
return mock(Handler.class);
}
}
// ...
}
Side note: Even though Mockito creates a named dynamic type, you almost certainly will not be able to hack it in and allow your code to create it by name. This is because the call to mock registers the instance within Mockito's internal state.
// BAD: Unlikely to work
#Test public void yourTest() {
objectUnderTest.methodUnderTest(
mock(Handler.class).getClass().getName());
// ...
}
Create a public method where you will place the logic to fetch the newInstance of the class
ClassA objectClassA=createNewInstance(className);
likewise,and
public ClassA createInstance(String className){
return (ClassA) (Class.forName(className)).newInstance();
}
Now suppose we were creating an instance of classA inside of ClassB
then in TestClass of B, we can simply mock this createInstance method
doReturn(mockClassA).when(mockClassB).createInstance(className);

Testing Private method using mockito

public class A {
public void method(boolean b){
if (b == true)
method1();
else
method2();
}
private void method1() {}
private void method2() {}
}
public class TestA {
#Test
public void testMethod() {
A a = mock(A.class);
a.method(true);
//how to test like verify(a).method1();
}
}
How to test private method is called or not, and how to test private method using mockito?
Not possible through mockito. From their wiki
Why Mockito doesn't mock private methods?
Firstly, we are not dogmatic about mocking private methods. We just
don't care about private methods because from the standpoint of
testing private methods don't exist. Here are a couple of reasons
Mockito doesn't mock private methods:
It requires hacking of classloaders that is never bullet proof and it
changes the api (you must use custom test runner, annotate the class,
etc.).
It is very easy to work around - just change the visibility of method
from private to package-protected (or protected).
It requires me to spend time implementing & maintaining it. And it
does not make sense given point #2 and a fact that it is already
implemented in different tool (powermock).
Finally... Mocking private methods is a hint that there is something
wrong with OO understanding. In OO you want objects (or roles) to
collaborate, not methods. Forget about pascal & procedural code. Think
in objects.
You can't do that with Mockito but you can use Powermock to extend Mockito and mock private methods. Powermock supports Mockito. Here's an example.
Here is a small example how to do it with powermock
public class Hello {
private Hello obj;
private Integer method1(Long id) {
return id + 10;
}
}
To test method1 use code:
Hello testObj = new Hello();
Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L));
To set private object obj use this:
Hello testObj = new Hello();
Hello newObject = new Hello();
Whitebox.setInternalState(testObj, "obj", newObject);
While Mockito doesn't provide that capability, you can achieve the same result using Mockito + the JUnit ReflectionUtils class or the Spring ReflectionTestUtils class. Please see an example below taken from here explaining how to invoke a private method:
ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test");
Complete examples with ReflectionTestUtils and Mockito can be found in the book Mockito for Spring.
Official documentation Spring Testing
By using reflection, private methods can be called from test classes.
In this case,
//test method will be like this ...
public class TestA {
#Test
public void testMethod() {
A a= new A();
Method privateMethod = A.class.getDeclaredMethod("method1", null);
privateMethod.setAccessible(true);
// invoke the private method for test
privateMethod.invoke(A, null);
}
}
If the private method calls any other private method, then we need to spy the object and stub the another method.The test class will be like ...
//test method will be like this ...
public class TestA {
#Test
public void testMethod() {
A a= new A();
A spyA = spy(a);
Method privateMethod = A.class.getDeclaredMethod("method1", null);
privateMethod.setAccessible(true);
doReturn("Test").when(spyA, "method2"); // if private method2 is returning string data
// invoke the private method for test
privateMethod.invoke(spyA , null);
}
}
**The approach is to combine reflection and spying the object.
**method1 and **method2 are private methods and method1 calls method2.
Think about this in terms of behaviour, not in terms of what methods there are. The method called method has a particular behaviour if b is true. It has different behaviour if b is false. This means you should write two different tests for method; one for each case. So instead of having three method-oriented tests (one for method, one for method1, one for method2, you have two behaviour-oriented tests.
Related to this (I suggested this in another SO thread recently, and got called a four-letter word as a result, so feel free to take this with a grain of salt); I find it helpful to choose test names that reflect the behaviour that I'm testing, rather than the name of the method. So don't call your tests testMethod(), testMethod1(), testMethod2() and so forth. I like names like calculatedPriceIsBasePricePlusTax() or taxIsExcludedWhenExcludeIsTrue() that indicate what behaviour I'm testing; then within each test method, test only the indicated behaviour. Most such behaviours will involve just one call to a public method, but may involve many calls to private methods.
Hope this helps.
I was able to test a private method inside using mockito using reflection.
Here is the example, tried to name it such that it makes sense
//Service containing the mock method is injected with mockObjects
#InjectMocks
private ServiceContainingPrivateMethod serviceContainingPrivateMethod;
//Using reflection to change accessibility of the private method
Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class};
Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params);
//making private method accessible
m.setAccessible(true);
assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null));
You're not suppose to test private methods. Only non-private methods needs to be tested as these should call the private methods anyway. If you "want" to test private methods, it may indicate that you need to rethink your design:
Am I using proper dependency injection?
Do I possibly needs to move the private methods into a separate class and rather test that?
Must these methods be private? ...can't they be default or protected rather?
In the above instance, the two methods that are called "randomly" may actually need to be placed in a class of their own, tested and then injected into the class above.
There is actually a way to test methods from a private member with Mockito. Let's say you have a class like this:
public class A {
private SomeOtherClass someOtherClass;
A() {
someOtherClass = new SomeOtherClass();
}
public void method(boolean b){
if (b == true)
someOtherClass.method1();
else
someOtherClass.method2();
}
}
public class SomeOtherClass {
public void method1() {}
public void method2() {}
}
If you want to test a.method will invoke a method from SomeOtherClass, you can write something like below.
#Test
public void testPrivateMemberMethodCalled() {
A a = new A();
SomeOtherClass someOtherClass = Mockito.spy(new SomeOtherClass());
ReflectionTestUtils.setField( a, "someOtherClass", someOtherClass);
a.method( true );
Mockito.verify( someOtherClass, Mockito.times( 1 ) ).method1();
}
ReflectionTestUtils.setField(); will stub the private member with something you can spy on.
I don't really understand your need to test the private method. The root problem is that your public method has void as return type, and hence you are not able to test your public method. Hence you are forced to test your private method. Is my guess correct??
A few possible solutions (AFAIK):
Mocking your private methods, but still you won't be "actually" testing your methods.
Verify the state of object used in the method. MOSTLY methods either do some processing of the input values and return an output, or change the state of the objects. Testing the objects for the desired state can also be employed.
public class A{
SomeClass classObj = null;
public void publicMethod(){
privateMethod();
}
private void privateMethod(){
classObj = new SomeClass();
}
}
[Here you can test for the private method, by checking the state change of the classObj from null to not null.]
Refactor your code a little (Hope this is not a legacy code). My funda of writing a method is that, one should always return something (a int/ a boolean). The returned value MAY or MAY NOT be used by the implementation, but it will SURELY BE used by the test
code.
public class A
{
public int method(boolean b)
{
int nReturn = 0;
if (b == true)
nReturn = method1();
else
nReturn = method2();
}
private int method1() {}
private int method2() {}
}
Put your test in the same package, but a different source folder (src/main/java vs. src/test/java) and make those methods package-private. Imo testability is more important than privacy.
In cases where the private method is not void and the return value is used as a parameter to an external dependency's method, you can mock the dependency and use an ArgumentCaptor to capture the return value.
For example:
ArgumentCaptor<ByteArrayOutputStream> csvOutputCaptor = ArgumentCaptor.forClass(ByteArrayOutputStream.class);
//Do your thing..
verify(this.awsService).uploadFile(csvOutputCaptor.capture());
....
assertEquals(csvOutputCaptor.getValue().toString(), "blabla");
Building on #aravind-yarram's answer: Not possible through mockito. From their wiki
So what's the OO way of testing private methods? Private methods with complex logic might be a sign that your class is violating the principle of single responsibility and that some of the logic should be moved to a new class.
Indeed, by extracting those private methods to public methods of more granular classes, you can unit test them without breaking the encapsulation of your original class.

Can I mock a super class method call?

Sometimes, you want to test a class method and you want to do an expectation on a call of a super class method. I did not found a way to do this expectation in java using easymock or jmock (and I think it is not possible).
There is a (relative) clean solution, to create a delegate with the super class method logic and then set expectations on it, but I don't know why and when use that solution ¿any ideas/examples?
Thanks
Well, you can if you want to. I don't know if you are familiar with JMockit, go check it out. The current version is 0.999.17 In the mean time, let's take a look at it...
Assume the following class hierarchy:
public class Bar {
public void bar() {
System.out.println("Bar#bar()");
}
}
public class Foo extends Bar {
public void bar() {
super.bar();
System.out.println("Foo#bar()");
}
}
Then, using JMockit in your FooTest.java you can validate that you're actually making a call to Bar from Foo.
#MockClass(realClass = Bar.class)
public static class MockBar {
private boolean barCalled = false;
#Mock
public void bar() {
this.barCalled = true;
System.out.println("mocked bar");
}
}
#Test
public void barShouldCallSuperBar() {
MockBar mockBar = new MockBar();
Mockit.setUpMock(Bar.class, mockBar);
Foo foo = new Foo();
foo.bar();
Assert.assertTrue(mockBar.barCalled);
Mockit.tearDownMocks();
}
Expanding on #Cem Catikkas answer, using JMockit 1.22:
#Test
public void barShouldCallSuperBar() {
new MockUp<Bar>() {
#Mock
public void bar() {
barCalled = true;
System.out.println("mocked bar");
}
};
Foo foo = new Foo();
foo.bar();
Assert.assertTrue(mockBar.barCalled);
}
No need for the static class annotated with #MockClass, it is replaced by the MockUp class.
I don't think I'd mock out a super call - it feels to me like the behaviour there is part of the behaviour of the class itself, rather than the behaviour of a dependency. Mocking always feels like it should be to do with dependencies more than anything else.
Do you have a good example of the kind of call you want to mock out? If you want to mock out a call like this, would it be worth considering composition instead of inheritance?
There are several tests that do just that (ie specify an expected invocation on a super-class method) using the JMockit Expectations API, in the Animated Transitions sample test suite. For example, the FadeInTest test case.
No, there is no way of mocking super class methods with jMock.
However there is a quick-and-dirty solution to your problem. Suppose you have class A and class B extends A. You want to mock method A.a() on B. You can introduce class C extends B in your test code and override the method C.a() (just call super, or return null, id does not matter). After that mock C and use the mock everywhere, where you'd use B.
intercepting a super call is much too fine-grained. Don't overdo the isolation.

Categories