集成测试时如何正确使用mockito?

How to use mockito correctly when conducting integration testing?

我有一个函数,我想在其中替换某些组成部分(余弦、正弦等)的行为,我正在尝试为这些部分创建一个模拟并将它们传递给函数。

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

问题是,我收到以下消息:

*org.mockito.exceptions.misusing.MissingMethodInvocationException: when() 需要一个必须为 'a method call on a mock' 的参数。 例如: 当(mock.getArticles()).thenReturn(文章); 此外,此错误可能会出现,因为:

  1. 您对以下任一方法存根:final/private/equals()/hashCode() 方法。 那些方法不能是stubbed/verified。 不支持在非 public 父级 类 上声明的模拟方法。
  2. 在 when() 中,您不是在 mock 上而是在其他对象上调用方法。*

None 个方法是私有的或最终的

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

在这种情况下,您正试图在实用程序 类 上模拟静态方法,这是 Mockito 不允许的。请参阅 Mocking static methods with Mockito 了解更多详情。

如果您在这里尝试测试的是数学的有效性,您可以简单地使用基本断言对它们进行单元测试。如果您想在测试中使用模拟,您可以探索上面 post 中建议的替代方案,或者重组您的代码以依赖 non-static 方法。

假设 Function1 只是传递给它的变量的持有者,对于每个要更改的内部 类:

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 MySin {
    public double mySin(double x, double accuracy) throws Exception {
        return MyCos.myCos(Math.PI/2 - x, accuracy);
    }
}

注意方法中删除的静态修饰符。