0

Let's say I have classA and classB:

public class A {
    private B b;

    public A(String id){
        this.b = new B(id);
    }

    public void doSomethingA(String id){
        // do somethingA
    }

}

public class B{
    public B(String id){
        // call anotherThing (id)
   }

    public void doSomethingB(){
        //somethingB
    }
}

now I want to test methods inside classA (with it's instance) but wanna mock classB

Mockito allows me to mock classB, but when I instantiate classA, the constructor calls classB (which I want to avoid)

Is there a way to mock only the constructor (either classA or classB) but not the other methods?

Mahyar
  • 1,011
  • 2
  • 17
  • 37
  • You can use PowerMockito to mock `new B(id)` call. See for example: http://benkiefer.com/blog/2013/04/23/powermockito-constructor-mocking/ – tsolakp Jan 17 '18 at 21:29
  • 1
    @tsolakp Dependencies that we want to isolate have to make part of the class API. Hiding them in the implementation is contradictory. – davidxxx Jan 17 '18 at 22:14
  • @davidxxx. Following your logic we should never directly create dependencies and should only use factories or DI. I find it too extreme, opinion based and don't agree that you need to avoid using static method calls, `new` constructs (such as for example with `new Date`) just for not using libraries like PowerMock. – tsolakp Jan 17 '18 at 23:06
  • @tsolakp I didn't say **never**. I said " Dependencies that we want to isolate". As we don't want to isolate them because we consider that they make part of internal, make the dependencies visible is an error and in this case we don't want mock them either. – davidxxx Jan 18 '18 at 04:03
  • @davidxxx. Thats my point. We should still be able to directly create dependencies in a class and mock them. It is another question if it makes sense to expose them. As for mocking private methods or dependencies it depends. There are 2 sides to this. One side says we should only do "grey" box unit testing and not worry about testing/mocking private method/dependencies. Other side says to do full white box testing including testing/mocking private methods as well. I am inclining more to the middle. Test private methods (and mock private dependencies if used) if it only has business logic. – tsolakp Jan 18 '18 at 16:35
  • @tsolakp In this case, I would also test but not really in this way. But as you said, it is a point of view. I understand the yours but I am not agree totally with with. Thanks you for sharing it. You could read this question : https://stackoverflow.com/questions/7075938/making-a-private-method-public-to-unit-test-it-good-idea?page=1&tab=oldest#tab-top It is interesting. I wrote a late answer. It explains my mind about testing private methods. – davidxxx Jan 18 '18 at 20:09
  • @davidxxx. Thanks for the link. – tsolakp Jan 18 '18 at 20:18

1 Answers1

3

You may mock any B object but you don't want to.
You want to mock the B b field of the A class.
Which is different.
You have to refactor your design and do B instantiation a dependency and not an internal processing.

A simple way is passing directly the B variable instead of the String as parameter :

public class A {
    private B b;

    public A(B b){
        this.b = b;
    }

    public void doSomethingA(String id){
        // do somethingA
    }

}

Now mocking is straight :

@Mock B b;

public void test(){    
  A a = new A(b);
}

An alternative way would be using a Function<String, B> .

public class A {
    private B b;

    public A(Function<String, B> bFunction, String id){
        this.b = bFunction.apply(id);           
    }

    public void doSomethingA(String id){
        // do somethingA
    }

}

Mocking becomes so :

@Mock B b;

public void test(){    
   A a = new A(s-> b, "anyValue");
}

And implementation code could instantiate A as :

A a = new A(B::new, "id");
davidxxx
  • 125,838
  • 23
  • 214
  • 215