Is the feature provided by Mockito 2 to mock final methods and final classes using org.mockito.plugins.MockMaker(mock-maker-inline) generally available(released) or still in the incubation phase. I am using mockito-core-2.23.4 artifact in my application. Need suggestions in mocking the final classes and methods. Is it advisable to use this approach or look for alternate options?
As of Mockito 2.x, Mockito now supports mocking of final classes and methods.
Example:
Say we have a MyList class shown below as the collaborator in test cases.
We’ll add a new finalMethod to this class:
public class MyList extends AbstractList {
final public int finalMethod() {
return 0;
}
}
And we'll also extend it with a final subclass:
public final class FinalList extends MyList {
#Override
public int size() {
return 1;
}
}
Before Mockito can be used for mocking final classes and methods, it needs to be configured.
We need to add a text file to the project's src/test/resources/mockito-extensions directory named org.mockito.plugins.MockMaker and add a single line of text:
mock-maker-inline
Mockito checks the extensions directory for configuration files when it is loaded. This file enables the mocking of final methods and classes.
Mock a Final Method:
Once Mockito is properly configured, a final method can be mocked like any other:
#Test
public void whenMockFinalMethodMockWorks() {
MyList myList = new MyList();
MyList mock = mock(MyList.class);
when(mock.finalMethod()).thenReturn(1);
assertNotEquals(mock.finalMethod(), myList.finalMethod());
}
By creating a concrete instance and a mock instance of MyList, we can compare the values returned by both versions of finalMethod() and verify that the mock is called.
Mock a Final Class:
Mocking a final class is just as easy as mocking any other class:
#Test
public void whenMockFinalClassMockWorks() {
FinalList finalList = new FinalList();
FinalList mock = mock(FinalList.class);
when(mock.size()).thenReturn(2);
assertNotEquals(mock.size(), finalList.size());
}
Similar to the test above, we create a concrete instance and a mock instance of our final class, mock a method and verify that the mocked instance behaves differently.
Reference: https://www.baeldung.com/mockito-final
Related
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.
I am having some trouble writing a unit test for my application. Currently, I am testing class A. In the method of class A I am testing, it makes a call to a helper class's method, which then calls another method inside the same helper class(getKeyObject) whose only function is to call a static method of a class contained in a framework I am using(buildKeyObject()). I am trying to stub getKeyObject() so that it returns a mock of the Object that is normally generated, but I have no idea on how to proceed.
One way I thought was to utilize PowerMockito and use PowerMockito.mockStatic(ClassInFramework.class) method to create a mock of the class in the framework I am using, and then use when(ClassInFramework.buildKeyObject()).thenReturn(KeyObjectMock), but due to some limitations on the work I am doing, I am forbidden to use PowerMockito. I am also unable to use Mockito.spy or the #spy annotation because of the same reasons.
class ATest{
public A aInstance = new A();
#Test
public void test(){
KeyObject keyObjectMock = Mockito.mock(KeyObject.class);
/*
between these 2 lines is more mockito stuff related to the KeyObjectMock above.
*/
String content = aInstance.method1();
Assert.assertEquals(content, "string")
}
}
class A{
public RandomClass d = new RandomClass()
public String method1(){
Helper helper = new Helper();
Object a = helper.method2()
return d.process(a);
}
}
class Helper{
public Object method2(){
KeyObject keyObject = getKeyObject();
Object object = keyObject.getObject();
return object;
}
public KeyObject getKeyObject(){
return ClassInFramework.buildKeyObject(); //static method call.
}
}
Can you guys help me with this?
Constructor injection is one of the common ways to do this. It does require you to modify the class under test for easier testing.
First, instead of creating a new Helper in the method, make it a member variable and assign it in the constructor.
class A {
private Helper helper;
// constructor for test use
public A(Helper helper) {
this.helper = helper;
}
// convenience constructor for production use
public A() {
this(new Helper());
}
}
Now, in your test, you can use the test constructor to inject any mock object derived from Helper. This can be done using Mockito or even simple inheritance.
class MockHelper extends Helper {
// mocked methods here
}
class ATest {
public A aInstance = new A(new MockHelper());
// ...
}
I have an abstract class that features no abstract methods... How would one go about testing this? Can I simply import it into a test class and go about business as usual?
Example:
public abstract class SomeAbstractClass implements SomeOtherClass {
// Some variables defined here
private static final String dbUrl = System.getProperty("db.url");
// Some public methods
public String doSomethingToUrl(String url) {
url = url + "/takeMeSomewhereNice";
}
}
Say I pass in an arg for db.url of localhost:8080, and I wanted to test that the doSomethingToUrl method did output the new string... Would it still be in this format?
public class TestUrl {
SomeAbstractClass sac = new SomeAbstractClass();
#Test
public void testUrlChange() throws Exception {
String testUrl = "localhost:8080";
assertThat("localhost:8080/takeMeSomewhereNice",
sac.doSomethingToUrl(testUrl));
}
}
You wouldn't be able to create an instance of just SomeAbstractClass, no - but you could create an anonymous subclass:
private SomeAbstractClass sac = new SomeAbstractClass() {};
You may well want to create a concrete subclass just for the sake of testing though - so that any time you do add abstract methods, you just need to put them there.
While I suspect you could use a mocking framework for this, I suspect it would add more complexity for little benefit, unless you need to check under what situations the abstract methods are called. (Mocks are great for interaction testing, but can be brittle for other purposes.) It could easily make for more confusing error messages (due to the infrastructure involved) as well.
You cannot initialize an abstract class, so your test class wouldn't compile as is.
You can either use an anonymous instance (the example below should suffice):
SomeAbstractClass sac = new SomeAbstractClass(){};
However, I would actually recommend you mock the class by means of a mocking framework such as Mockito or EasyMock.
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
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.