53

I want to test some methods that call others in the same class. They are basically the same methods, but with different numbers of arguments because there are some default values in a database. I show on this

public class A{
    Integer quantity;
    Integer price;        

    A(Integer q, Integer v){
        this quantity = q;
        this.price = p;
    }

    public Float getPriceForOne(){
        return price/quantity;
    }

    public Float getPrice(int quantity){
        return getPriceForOne()*quantity;
    }
}

So I want to test if the method getPriceForOne() was called when calling the method getPrice(int). Basically call getPrice(int) as normal and mock getPriceForOne.

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
....

public class MyTests {
    A mockedA = createMockA();

    @Test
    public void getPriceTest(){
        A a = new A(3,15);
        ... test logic of method without mock ...

        mockedA.getPrice(2);
        verify(mockedA, times(1)).getPriceForOne();
    }
}

Please keep in mind that I have a much more complicated file that's a utility for others and they must all be in one file.

Perlos
  • 2,028
  • 6
  • 27
  • 37
  • What you want is partial mocking but is not recommended, Mockito actually discourage this at exception of some specific cases. If it's a utility class, it makes sense to just fully test each methods. If it's not, ie it requires complex processing, you might want to design your code with composition instead. – bric3 Jan 06 '12 at 11:31

1 Answers1

90

You would need a spy, not a mock A:

    A a = Mockito.spy(new A(1,1));
    a.getPrice(2);
    verify(a, times(1)).getPriceForOne();
denis.solonenko
  • 11,645
  • 2
  • 28
  • 23
  • 4
    What is **getPriceForOne** is supposed to have some arbitrary parameters? – IgorGanapolsky Mar 07 '17 at 15:35
  • 1
    then you just add `any(YourObject.class)` as a parameter for `getPriceForOne` – TormundThunderfist Jun 02 '17 at 05:57
  • Doing this is correct. Same time, if your 'spyed' class have private variables to set, those also need to set to that class using Whitebox.setInternalState() method. – udayanga Sep 22 '17 at 11:19
  • in `verify(a, times(1))`, you can skip the second param: is redundant. Doing do would improve readability and succinctness. See documentation and implementation of `Mockito.verify`: ``` public static T verify(T mock) { return MOCKITO_CORE.verify(mock, times(1)); } ``` – Clint Eastwood Dec 18 '17 at 15:45
  • Is it possible to return a boolean to indicate if it has been called or not, instead of failing the test outright? – djkelly99 Apr 20 '18 at 11:11
  • 1
    You can use a try/catch if you want to prevent the test from failing, but its not typically a good idea to have logic like that in your test. You shouldn't need conditionals because ideally your code would work the same way each time you run the test – Brandon Jan 16 '20 at 01:40