156
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?

wittich
  • 2,079
  • 2
  • 27
  • 50
Nageswaran
  • 7,481
  • 14
  • 55
  • 74
  • 1
    If you owns the code base, you should create one public method, which calls private method. if you did not owns the code and you still have to write test for private method (really!), then use powermock. https://github.com/powermock/powermock/wiki/MockPrivate – Himeshgiri gosvami May 01 '23 at 07:40

13 Answers13

154

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.

KeatsPeeks
  • 19,126
  • 5
  • 52
  • 83
Aravind Yarram
  • 78,777
  • 46
  • 231
  • 327
  • 41
    There is a fatal assumption made by that statement: >Mocking private methods is a hint that there is something wrong with OO understanding. If I'm testing a public method, and it calls private methods, I would want to mock private method returns. Going by the above assumption obviates the need to even _implement_ private methods. How is that a poor understanding of OO? – eggmatters Jan 08 '20 at 22:24
  • 8
    @eggmatters According to Baeldung "Mocking techniques should be applied to the external dependencies of the class and not to the class itself. If mocking of private methods is essential for testing our classes, it usually indicates a bad design." Here is a cool thread about it https://softwareengineering.stackexchange.com/questions/100959/how-do-you-unit-test-private-methods – Jason Glez Feb 08 '20 at 02:19
  • 1
    if you see object as the thing to test it might be right. but if you want to test functionality then the functions are the thing you want to go for. functions are for modularisation and having a module would mean to verify it first to a sane degree before verifying anything that uses it - this eases and improves overall testing results quality. – Alexander Stohr Apr 16 '21 at 07:50
  • 2
    The OO 'trick' to test private method logic is to actually to create new classes having those private methods as public methods. This way you can unit test your new more granular classes, testing the previously private logic. Complex private method logic can indeed be a sign that your class has more than one responsibility and might be better broken down in more granular classes. – Heschoon Oct 04 '21 at 15:32
102

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.

David Newcomb
  • 10,639
  • 3
  • 49
  • 62
shift66
  • 11,760
  • 13
  • 50
  • 83
  • 29
    I am confused with this answer. This is mocking, But the title is testing the private methods – diyoda_ Jun 06 '17 at 21:57
  • I have used Powermock to mock the private method, but how can I test the private method with Powermock. Where, I can pass some input and expect some output from the method and then verify the output? – Rito Oct 27 '17 at 20:42
  • You cant.You mock input output, you cannot test the real functionality. – Talha Mar 20 '18 at 10:52
  • @diyoda_ The author wants to verify the method is called, that that has to be done by mocking. You can verify mocks only unfortunately. – devaga Jan 12 '21 at 09:36
50

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);
Mindaugas Jaraminas
  • 3,261
  • 2
  • 24
  • 37
44

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:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ComTurretaSpringReflectionReflectiontestutilsApplicationTests {

    @Test
    public void test01()
    {
        Student student = new Student();
        student.setName("James Dean");

        System.out.println("Before: " + student.toString());
        ReflectionTestUtils.setField(student, "internalCode", 1343243);

        System.out.println("After: " + student.toString());

        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

jumping_monkey
  • 5,941
  • 2
  • 43
  • 58
AR1
  • 4,507
  • 4
  • 26
  • 42
  • ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "argument1", "argument2", "argument3" ); The last argument of invokeMethod, uses Vargs which can take multiple arguments that needs to passed to the private method. it works. – Tim Aug 13 '19 at 20:55
  • 3
    This answer should have more upvotes, by far the easiest way to test private methods. – maxeh Sep 08 '19 at 12:24
  • what about knowing if a private method has been called? – Artanis Zeratul Oct 19 '22 at 01:38
  • @ArtanisZeratul it depends on your use case. In general if you want to know if a private method has been called, then you can use Mockito Verify. If you need better examples, please post a question and we'll take it there. – AR1 Oct 21 '22 at 13:08
23
  1. 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);
    
        }
    }
    
  2. 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.

Singh Arun
  • 320
  • 2
  • 5
17

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.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
8

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));
7

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.

Jaco Van Niekerk
  • 4,180
  • 2
  • 21
  • 48
  • 34
    A valid point. However, isn't it the reason for using a private modifier for methods is because you simply want to chop down codes that are too lengthy and/or repetitive? Separating it as another class is like you're promoting those lines of codes to be first class citizens which won't get reused anywhere else because it was meant specifically to partition lengthy codes and to prevent repeating lines of codes. If you're going to separate it to another class it just doesn't feel right; you would easily get class explosion. – supertonsky Feb 27 '13 at 09:53
  • 2
    Noted supertonsky, I was referring to the general case. I agree that in the above case it should not be in a separate class. (+1 on your comment though - it is a very valid point you're making on promoting private members) – Jaco Van Niekerk Feb 28 '13 at 05:35
  • 5
    @supertonsky, I have been unable to find any satisfactory response to this problem. There are several reasons why I might use private members and very often they do not indicate a code smell and I would benefit greatly from testing them. People seem to brush this off by saying "just don't do it". – LuddyPants Jan 27 '14 at 19:34
  • 3
    Sorry, I opted to downvote based on "If you 'want' to test private methods, it may indicate you need to downvote your design". OK, fair enough, but one of the reasons to be testing at all is because, under a deadline when you don't have time to be rethinking the design, you're trying to safely implement a change that needs to be made to a private method. In an ideal world would that private method not need to be changed because the design would be perfect? Sure, but in a perfect world, but it's moot because in a perfect world who needs tests, it all just works. :) – John Lockwood Mar 12 '14 at 16:30
  • 2
    @John. Point taken, your downvote warranted (+1). Thanks for the comment as well - I agree with you on the point you make. In such cases I can see one of two options: Either the method is made package-private or protected and unit tests written as usual; or (and this is tongue-in-cheek and bad practice) a main method is quickly written to make sure it still works. However, my response was based on a scenario of NEW code being written and not refactoring when you may not be able to tamper with the original design. – Jaco Van Niekerk Mar 13 '14 at 08:31
  • 2
    Moving methods to their own class, or making them public, just for the sake of enabling functionality in a testing suite is definitely bad practice. And "You're not suppose to test private methods." I strongly disagree. Private methods have their own complexity and are therefore completely reasonable to test. – Luke Aug 19 '19 at 19:27
  • 1
    THis. A private method is not part of a contract and therefore should not be a concern of a unit test. Unit testing private methods or in other words to write private method dependant unit tests _is_ a bad practice. – NotGaeL Sep 30 '20 at 16:15
5

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.

Fan Jin
  • 2,412
  • 17
  • 25
3

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):

  1. Mocking your private methods, but still you won't be "actually" testing your methods.

  2. 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.]

  3. 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() {}
    
    }
    
Reji
  • 3,426
  • 2
  • 21
  • 25
2

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.

Roland Schneider
  • 3,615
  • 3
  • 32
  • 43
  • 6
    The only legitimate reason is to test a part of a legacy system. If you begin to test private/package-private method, you expose your object internals. Doing so usually results in poor refactorable code. PRefer composition so you can achieve testability, with all the goodness of an object oriented system. – bric3 Jan 10 '12 at 07:53
  • 1
    Agreed - that would be the preferred way. However, if you really want to test private methods with mockito, this is the only (typesafe) option you have. My answer was a bit hasty though, I should have pointed out the risks, like you and the others have done it. – Roland Schneider Jan 10 '12 at 20:28
  • This is my preferred way. There is nothing wrong to expose object internal in package-private level; and unit test is white-box testing, you need to know the internal for testing. – Andrew Feng Jan 25 '17 at 00:47
0

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");
milensky
  • 1
  • 1
-1

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.

Heschoon
  • 2,915
  • 9
  • 26
  • 55