您如何在JMockit中模拟单例依赖项?

时间:2019-01-26 03:47:32

标签: jmockit java-11

我正在为机器人进行一些自动化的单元和集成测试。可以想象,机器人有很多传感器对象,因此在测试过程中需要模拟。

依赖项之一是单例设计,除了自身之外,其他任何实例都不能实例化。据我了解(我是JMockit的新手),一旦用@Mocked注释了一个类,便会模拟它的所有方法和构造函数。 JMockit Documentation

  

在声明模拟字段和参数时,可以使用三种不同的模拟注释:@Mocked,它将在模拟类的所有现有实例和将来的实例上模拟所有方法和构造函数。

但是,我注意到(通过使用断点)正在调用真实类的构造函数,并且无法访问传感器,从而导致测试失败。

这是我要模拟的单例的相关部分。请注意,我无法修改此类:

public class DriverStation() {
    // This line in particular is an issue.
    private static DriverStation currentInstance = new DriverStation();

    public static DriverStation getInstance() {
        return DriverStation.instance;
    }

    private DriverStation() {
        // This constructor cannot be called during tests.
    }
}

这是我的测试代码:

public class BlingControllerTest {
    @Mocked
    private DriverStation station;

    @Tested
    private BlingController blingController;

    /**
     * Tests getting the robot's operation period while not in a real match.
     */
    @Test
    public void testGetOperationPeriodDuringRealMatch(@Mocked DriverStation station) {
        new Expectations(DriverStation.class) {{
            DriverStation.getInstance();
            result = station;

            station.isFMSAttached();
            result = true;

            station.isAutonomous();
            returns(true, false);
        }};
    }
}

Full source also available on GitHub

我还应该提到,出于某种原因,在测试期间本地调用单例构造函数不是问题,但是当测试在travis-ci上运行时,这是一个问题。

在travis-ci上运行的Stacktrace:

ca.team2706.frc.robot.commands.bling.BlingControllerTest > testGetOperationPeriodDuringRealMatch STANDARD_ERROR
    java.io.IOException: wpiHaljni could not be loaded from path or an embedded resource.
        attempted to load for platform /linux/x86-64/
        at edu.wpi.first.wpiutil.RuntimeLoader.loadLibrary(RuntimeLoader.java:79)
        at edu.wpi.first.hal.JNIWrapper.<clinit>(JNIWrapper.java:25)
        at edu.wpi.first.wpilibj.DriverStation.<init>(DriverStation.java:194)
        at edu.wpi.first.wpilibj.DriverStation.<clinit>(DriverStation.java:132)
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:398)
        at mockit.internal.state.TestRun.ensureThatClassIsInitialized(TestRun.java:138)
        at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineType(BaseTypeRedefinition.java:65)
        at mockit.internal.expectations.mocking.TypeRedefinition.redefineType(TypeRedefinition.java:28)
        at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldType(FieldTypeRedefinitions.java:78)
        at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldType(FieldTypeRedefinitions.java:65)
        at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldTypes(FieldTypeRedefinitions.java:53)
        at mockit.internal.expectations.mocking.FieldTypeRedefinitions.<init>(FieldTypeRedefinitions.java:33)
        at mockit.integration.TestRunnerDecorator.handleMockFieldsForWholeTestClass(TestRunnerDecorator.java:142)
        at mockit.integration.TestRunnerDecorator.updateTestClassState(TestRunnerDecorator.java:40)

感谢您的帮助。

0 个答案:

没有答案