How to cover the Class instantiated inside a method in Mockito Junit? - java

How can I cover the class instantiated inside a method and need to get the value that is not set.
Here is my Service class DemoClass.Java
public class DemoClass{
public void methodOne(){
ClassTwo classTwo=new ClassTwo();
classTwo.setName("abc");
customerRepo.save(classTwo);
ClassThree classThree=new ClassThree();
classThree.setId(classTwo.getId()); //here causing NullPointerException as ClassTwo is instantiated inside the method and the id value is not set and the test stops here.
classThree.setName("person1");
classThree.setUpdatedBy("person2");
}
}
As the classTwo is instantiated in the method level the test method does not get the getId(). And I can't change or add anything to the Controller class. The test stops at that line and causing NullPointerException as it doesn't know the value classtwo.getId() as it is not set. I need to cover that/ pass that line in the test class.
I tried mocking that class and spy also. Any Mockito solutions available for this.
The Id in ClassTwo is an autogenerated sequence number so no need of setting in DemoClass.Java
Here is my test class DemoClassTest.Java
#RunWith(MockitoJunitRunner.Silent.class)
public void DemoClassTest(){
#InjectMocks
DemoClass demoClass;
#Test
public void testMethodOne(){
demoClass.methodOne()
}

You could provide a customerRepo test double that just sets some specific id on classTwo:
public class TestCustomerRepo extends CustomerRepo {
public void save(ClassTwo classTwo) {
classTwo.setId(4711L);
}
}
But since you seem to be testing JPA code it would probably be a better idea to perform an integration test containing an actual database instead.

I usually do it like this:
long testId = 123;
Mockito.when(customerRepo.save(Mockito.any())).thenAnswer(invocation -> {
ClassTwo entity = (ClassTwo)invocation.getArgument(0);
entity.setId(testId);
return entity;
});
If you want to assert something on the ClassThree entity, do a Mockito.verify on the ClassThree repository mock.

Related

Mockito how to mock a private method [duplicate]

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.

Mocking public method inside a private method

I have a class like below:
public class ClassOne {
public function1(input, output, context) {
//some implementation
private function2(List, String, String);
}
private void function2(List, String, String){
Class2 class2 = new Class2();
String value = class2.method1(string, string);
}
}
public Class2 {
public String method2(string, string) {
//some implementation
return string;
}
}
I am writing Unit test for ClassOne using Mockito and PowerMockito and would like to mock the call to class2 and do not want to actually call method body for method2. How can I achieve this?
I tried Mockito.mock and PowerMockito.spy the class and when(class2.method2).thenReturn() and doReturn().when(class2).method2(); but everything calls the method body when I do classOne.function1. I have spied the ClassOne.
It would be really helpful if you would have also provided your non working Unit Tests. On the other hand I'm pretty sure the problem isn't there anyway :)
Your problem is not that Mockito & PowerMockito are not working.
The real problem is in the dependency of you classes. Or to be more specific the way your classes handle this dependency.
In General it is not a good idea to instantiate the dependency (Class2) in the place it is needed (ClassOne). As you can see right now it makes testing pretty hard.
It would be better to pass the dependency into the class that needs it.
This is called Dependency Injection (DI).
In your example you would pass an object of Class2 into the constructor of ClassOne. The Code would look something like that:
public class ClassOne {
private final Class2 class2;
public ClassOne(Class2 class2) {
this.class2 = class2;
}
...
private void function2(List, String, String){
String value = class2.method1(string, string);
}
}
As you can see you simply pass an instance of your dependency and use this one instead of creating it on your own.
In your Unit Test you are now able to pass a Mock of Class2 into your Class1 object which will then be used.

PowerMockito doesn't mock the new instance called in the tested class

I have the following class where, in the constructor, I call another constructor to build a field of the class:
public class ClassIWantToTest {
private ClassIWantToMock anotherClass;
public ClassIWantToTest() {
//some stuff
anotherClass = new ClassIWantToMock(); //<-- call constructor to build the field
//some other stuff
}
}
When I test the class ClassIWantToTest, I want to mock the instance of ClassIWantToMock.
Hence, I've set up my test as follows:
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassIWantToMock.class)
public class ClassIWantToTest_Test {
#Test
public void myFirstTest() {
ClassIWantToMock myMock = PowerMockito.mock(ClassIWantToMock.class);
PowerMockito.whenNew(ClassIWantToMock.class).withAnyArguments().thenReturn(myMock);
ClassIWantToTest test = new ClassIWantToTest(); //<-- not mocked
}
}
However, in the last line of code in the test (where I make a new of the class I want to test), the constructor of ClassIWantToMock is still called.
I've searched other examples on Stack Overflow (and in documentation), but it seems that it should be done like this. What am I forgetting/doing wrong?
It was indeed a simple mistake. If the class ClassIWantToMock is initialized inside ClassIWantToTest, then also ClassIWantToTest should be prepared for test.
I replaced this:
#PrepareForTest(ClassIWantToMock.class)
with this:
#PrepareForTest({ClassIWantToTest.class,ClassIWantToMock.class})
... and it worked fine.

Mockito/PowerMockito mocking private factory method

I want to use pattern 1 suggested in the following link:
https://code.google.com/p/mockito/wiki/MockingObjectCreation
and have the following class:
public class MyClass {
private AnyType anyObject;
private Foo foo; // Foo is a thirdparty class
public MyClass(AnyType anyObject) {
//...
foo = makeFoo();
}
private Foo makeFoo() {
return new Foo();
}
}
I'm trying to make a test as follows:
#Test
public void myTestMethod() {
MyClass myClass = Mockito.spy(new MyClass());
// now i want to do something like this:
Foo mockFoo= Mockito.mock(Foo.class);
// Mockito.doReturn(mockFoo).when(myClass).makeFoo());
}
The problem is my factory method makeFoo is a private method, so I can't access it. I don't want to make it public just for the test. My test classes are not in the same package as my productive code either, so making it visible only for the package won't work.
Update:
Now i found another problem. Assumed that makeFoo() is public, 'mockFoo' will not be returned either, yet the real makeFoo() method is invoked. This happens since the invocation of makeFoo() (in the constructor of MyClass) is prior to the creation of mockFoo.
Does anyone know how to solve this problem or am I doing something totally wrongly?
Thanks you guys in advance for helping!!
Have a look at whenNew of PowerMockito. This allows to "overwrite" the constructor call of an object and return a mock of it instead.
http://powermock.googlecode.com/svn/docs/powermock-1.3.7/apidocs/org/powermock/api/mockito/PowerMockito.html#whenNew%28java.lang.Class%29
http://www.gitshah.com/2010/05/how-to-mock-constructors-using.html
If you just need to set a field inside your class, it's doable with MockitoAnnotations
You just need to create fields you need, annotate them and in unit test before section call MockitoAnnotations.initMocks(this)
In your case it will look like:
#Spy
#InjectMocks
MyClass myClass;
#Mock
Foo foo;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
Please read also documentation above.

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.

Categories