Using mocks within a constructor - java

Is it possible to use mocks within a constructor?
Class A{
public B b = new B();
public A( String input ){
//I need to stub this method
b.someMethod( input );
}
// Class implementations
}
Unit Test:
Class ATest{
#Mock
B b;
#InjectMock
A a;
//option1:
#Before
setup(){
MockitoAnnotations.initMocks( this ); //Fails - since A isnt instantiated
a = new A();
}
//option2:
#Before
setup(){
a = new A();
MockitoAnnotations.initMocks( this ); // Fails in new A() due to method i want to stub as mocks werent initialized yet !
}
}
How can i approach this? thanks in advance.

This kind of design is hard to mock, and reveals a possible design flaw or at least weakness in your class under test. It probably calls for some kind of injection framework (i.e. Spring), so that you aren't explicitly calling the B constructor. Then your second test attempt would be spot on
If Spring is too heavy handed, there are lighter injection frameworks. Or finally, you could just pass B in as a constructor argument for A. Then you would have to use Mockito.mock(B.class) to make your B mock before passing it into the A constructor (and then you would forgo the use of the Mockito annotations).

I don't understand precisely what you are trying to do from this, but your second approach is correct. Only you need to instantiate the B class just as you did for A class. So, basically this is all you will need to do:
//option2:
#Before
setup(){
a = new A();
b = new B();
MockitoAnnotations.initMocks( this ); // Fails in new A() due to method i want to stub as mocks werent initialized yet !
}
}

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.

How to create mockito test for Manual dependency injection

I am creating manual dependency injection using java. I am trying to create Mockito test for the same.
As I am new to Mockito and I have done only for framework based before. So need your help on the below
//All Business logic holder class. It does not have any new operator. Even, it does not have any knowledge about the concrete implementations
class MyClass {
private MyProto a;
private B b;
private C c;
MyClass(MyProtoImpl a, B b, C c) {
//Only Assignment
this.a = a;
this.b = b;
this.c = c;
}
//Application Logic
public void doSomething() {
a.startClient(c);
//Do B specific thing
//Do C specific thing
}
}
//The Factory. All the new operators should be placed in this factory class and wiring related objects here.
class MyFactory {
public MyClass createMyClass() {
return new MyClass(new AImpl(), new BImpl(), new CImpl());
}
}
class Main {
public static void main(String args[]) {
MyClass mc = new MyFactory().createMyClass();
mc.doSomething();
}
}
So at last I need to achieve two things.
To Test MyFactory class and MyClass
To Test MyProtoImpl class. So in this way I can get the entire codecoverage. So not only MyProtoImpl need to be covered with Junit Mockito MyFactory and MyClass also need to be covered
Normally you want to create mocks of your dependencies. From the comments it seems that you want to test the classes in separation, hence I would suggest "unit testing" the modules. I will walk you through the testing of MyClass.
class MyTestClass {
// First you want to create mocks of your dependencies
#Mock
MyProto a;
#Mock
B b;
#Mock
C c;
// At this point Mockito creates mocks of your classes.
// Calling any method on the mocks (c.doSomething()) would return null if the
// method had a return type.
#Test
void myFirstTest(){
// 1. Configure mocks for the tests
// here you configure the mock's returned values (if there are any).
given(a.someMethod()).willReturn(false);
// 2. Create the SUT (Software Under Test) Here you manually create the class
// using the mocks.
MyClass myClass = new MyClass(a, b, c);
// 3. Do the test on the service
// I have assumed that myClass's doSomething simply returns a.someMethod()'s returned value
boolean result = myClass.doSomething();
// 4. Assert
assertTrue(result);
// Alternatively you can simply do:
assertTrue(myClass.doSomething());
}
}
If your classes contain void methods, you can test whether the methods have been called with the correct arguments:
verify(a).someMethod(someParameter);
That's pretty much it for Mockito. You create mocks, you set the desired behavior, and finally you assert the result or verify that the methods have been called with the correct arguments.
However I don't think it makes that much sense to "Mockito-test" classes that are responsible for database connections and similar configuration. Mockito testing is IMHO more suited to test the service/logic layer of the application. If you had a spring project I would simply test such configuration classes (i.e. database config etc.) in a scenario, where i establish a real connection to the database.

How to spy on a Method that belongs to an object not accessible from outside?

I'm very new to Mockito and I have a situation for which I can't find a solution. There's a method that I want to test using Mockito. The problem is that inside this method, there's an object created and that object has a function that I want to mock.
So for example, here is a small sample code which illustrates my issue:
public class ClassA {
public functionDoingDBStuff() {
//...........
}
}
public class ClassB {
final ClassA classAObj = null;
public functionXYZ() {
classAObj = new ClassA();
classAObj.functionDoingDBStuff();
}
}
#Test
MyTestFunction() {
ClassB classBObj = new ClassB();
// How can I access and mock functionDoingDBStuff() here?
}
So in MyTestFunction(), I want to test functionXYZ(), but mock the function functionDoingDBStuff() that is called inside functionXYZ(). By mock, I mean return a specific result that I want for the test. However function functionDoingDBStuff() belongs to an object that's created inside functionXYZ(), so I don't know how I can tell Mockito to access it from within MyTestFunction(). I hope you're able to understand what I mean.
To me if a piece of code can't be easily tested that suggests a problem with the structure of the code. Anyway, why does new ClassA() need to be done inside the functionXYZ? Can't be instantiated (better still injected) at Object level? If so you can inject a mock instance of ClassA.
If it still has to be instantiated within the method, may be instead of doing new ClassA(), it should be wrapped inside a factory method. Then you can mock the factory to return a mock ClassA.

Mockito ClassCastException

The method I want to test has a for loop with logic for each element in bList:
class A {
void someMethod(){
for(B b: bList){
//some logic for b
}
}
}
I get an exception when executing following test:
#RunWith(MockitoJUnitRunner.class)
class ATest {
#Mock
private B b;
#Mock
private Map<Int, List<B>> bMap;
#Mock(answer = Answers.RETURNS_DEEP_STUBS)
private List<B> bList;
#Spy
#InjectMocks
private C c;
....
#Test
public void test(){
//this line executes fine
when(bList.size()).thenReturn(1);
//strangely this works fine
when(bMap.get(any())).thenReturn(bList);
//ClassCastException
when(bList.get(0)).thenReturn(b); // or when(bList.get(anyInt())).thenReturn(b);
c.methodIWantToTest();
}
}
The exception I get is:
java.lang.ClassCastException:
org.mockito.internal.creation.jmock.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$ cannot be cast to xyz.B
Has anyone encountered this before and come up with a workaround?
I have searched for a solution and have come across some links:
http://code.google.com/p/mockito/issues/detail?id=251
and
http://code.google.com/p/mockito/issues/detail?id=107
As this link you posted indicates, you've encountered a bug with Answers.RETURNS_DEEP_STUBS.
I don't actually see any reason to actually use RETURNS_DEEP_STUBS in your example code. You really should try to evaluate whether or not you need deep stubs, because, as the Mockito docs say, "every time a mock returns a mock a fairy dies." So if you can, just take that out and your example will work.
However, if you insist on using deep stubs, you can hack around this error by up-casting the return value from the method call to Object. For example, replace the offending line in your code with this:
when((Object)bList.get(0)).thenReturn(b);
All that being said, I personally agree with #jhericks. The best solution is probably to use an actual ArrayList which contains your mock as opposed to mocking List. The only problem is getting your list injected, so you'd have to use #Spy. For example:
#RunWith(MockitoJUnitRunner.class)
class ATest{
private B b = mock(B.class);
#Spy
private List<B> bList = new ArrayList<B>() {{ add(b); }};
#InjectMocks
private C c = new C();
#Test
public void test(){
c.methodIWantToTest();
// verify results
}
}
Unfortunately this is not possible
Case: tests on API:
interface ConfigurationBuilder {...}
configurationBuilder.newServerAction("s1").withName("111")....create();
Main reason of this usage is compatibility maintenance on compile time.
But mockito cannot support generics in chains with RETURNS_MOCKS and RETURNS_DEEP_STUBS options due to type erasure in java:
Builder/*<ServerActionBuilder>-erasured generic*/ b = configurationBuilder.newServerAction("s1");
b.withName("111")...create();
Result in example above should be ServerAction but in mockito it is Object of generated class.
see Issue: Can not Return deep stubs from generic method that returns generic type #484

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