Home > front end >  How to use mockito correctly when conducting integration testing?
How to use mockito correctly when conducting integration testing?

Time:04-04

I have a function in which I want to substitute the behavior of some component parts (cosines, sines, ...), I'm trying to create an mock for these parts and pass them to the function.

class Function1Test {
private static final double accuracy = 10e-5;
static Function1 firstFunction;
static Function2 secondFunction;
static TrFunc.MyCos cos;
static TrFunc.MySin sin;
static TrFunc.MyTan tan;
static TrFunc.MySec sec;
static LgFunc.Log2 log2;
static LgFunc.Log3 log3;
static LgFunc.Log5 log5;
static LgFunc.Log10 log10;
static Func_System sys;
@BeforeAll
static void setUp() {
    cos = mock(TrFunc.MyCos.class);
    sin = mock(TrFunc.MySin.class);
    tan = mock(TrFunc.MyTan.class);
    sec = mock(TrFunc.MySec.class);
    firstFunction = new Function1(cos, sin, tan, sec);
    log2 = mock(LgFunc.Log2.class);
    log3 = mock(LgFunc.Log3.class);
    log5 = mock(LgFunc.Log5.class);
    log10 = mock(LgFunc.Log10.class);
    secondFunction = new Function2(log2, log3, log5, log10);
    sys = new Func_System(firstFunction, secondFunction);
}

static Stream<Arguments> valuesRangeProvider(){
    return Stream.of(
            arguments(-6.282185307179586, 1001001.3330000667),
            arguments(-0.161592653589793, 33.496935752492160)
    );
}
@DisplayName("Integration Test with Mocks")
@ParameterizedTest(name = "{index}: Check range of values, x = {0}")
@MethodSource("valuesRangeProvider")
void test_0(double value, double expected) throws Exception {
    when(firstFunction.sin.mySin(value, accuracy)).thenReturn(sin(value));
    when(firstFunction.cos.myCos(value, accuracy)).thenReturn(cos(value));
    when(firstFunction.tang.myTan(value, accuracy)).thenReturn(sin(value)/cos(value));
    when(firstFunction.sec.mySec(value, accuracy)).thenReturn(1/cos(value));
    assertEquals(expected, firstFunction.calculate(value, accuracy), accuracy);
}

The thing is, I get the following message:

*org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles); Also, this error might show up because:

  1. you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods declared on non-public parent classes is not supported.
  2. inside when() you don't call method on mock but on some other object.*

None of the methods are private or final

public class TrFunc {
public static class MyCos {
    public static double myCos(double x, double accuracy) throws Exception {
        if (accuracy < 0){
            throw new Exception("The accuracy below zero");
        }
        double theta_norm = Math.abs(x);
        theta_norm -= Math.floor(theta_norm/Math.PI/2)*2*Math.PI;
        double result = 1;
        double step = 1;
        int i;
        for (i = 1; step > accuracy && i != Integer.MAX_VALUE; i  ){
            step = step*theta_norm*theta_norm/(2*i-1)/(2*i);
            if (i % 2 == 1){
                result -= step;
            } else {
                result  = step;
            }
        }
        if (!Double.isFinite(result) || i == Integer.MAX_VALUE-1){
            throw new Exception("Too many iterations");
        }
        return result;
    }


    private static double factorial(int numer) {
        double factorial = 1.0d;

        while (numer != 0) {
            factorial *= numer--;
        }

        return factorial;
    }
}

public static class MySin {
    public static double mySin(double x, double accuracy) throws Exception {
        return MyCos.myCos(Math.PI/2 - x, accuracy);
    }
}

public static class MyTan {
    public static double myTan(double x, double accuracy) throws Exception {
        double divisor =  MyCos.myCos(x, accuracy);
        if (Math.abs(divisor) <= accuracy) throw new Exception("Division by zero");
        return MySin.mySin(x, accuracy) / divisor;
    }
}

public static class MySec {
    public static double mySec(double x, double accuracy) throws Exception {
        double divisor =  MyCos.myCos(x, accuracy);
        if (Math.abs(divisor) <= accuracy) throw new Exception("Division by zero");
        if ((x   Math.PI / 2) / Math.PI % 1 == 0) throw new Exception("x can't be Pi*n-Pi/2");
        return 1 / divisor;
    }
}
}

CodePudding user response:

In this case, you are attempting to mock static methods on your utility classes, which is not allowed by Mockito. Please see Mocking static methods with Mockito for more details.

If what you are attempting to test here is the validity of your math, you can simply unit test them with basic assertions. If you would like to use mocks for your test, you can explore alternatives suggested in the above post, or restructure your code to rely on non-static methods.

Assuming that Function1 is just a holder for the variables passed into it, for each of the inner classes you want to change:

public static class MySin {
    public static double mySin(double x, double accuracy) throws Exception {
        return MyCos.myCos(Math.PI/2 - x, accuracy);
    }
}

to

public static class MySin {
    public double mySin(double x, double accuracy) throws Exception {
        return MyCos.myCos(Math.PI/2 - x, accuracy);
    }
}

Note the removed static modifier on the method.

  • Related