mockito 单元测试中的模拟对象构造

eeq64g8w  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(85)

我想为一个类编写单元测试,它创建了一个有问题的类的示例,我在以下约束下工作:
1.我的类调用一些第三方库初始化代码。
1.第三方代码创建有问题的类的示例。这很好,为了不改变第三方库的行为,我应该用mock替换这个示例。
1.我的类创建了一个有问题的类的示例。我应该嘲笑对象构造;例如,我会让有问题的对象构造函数抛出一个异常。
我正在使用Mockito 5.5.0JUnit Jupiter 5.9.3
下面是一个非常简单的例子:

class Problematic {

    public Problematic(String description) {
        System.out.println("Problematic object constructed: " + description);
    }
}

class ThirdPartyLibrary {

    public static void thirdPartyCode() {
        new Problematic("this is fine");
    }
}

class MyClass {

    public static void myCode() {
        ThirdPartyLibrary.thirdPartyCode();
        new Problematic("this needs to be mocked");
    }
}

class MockProblematicObjectConstructionTest {

    @Test
    void test() {
        try (MockedConstruction mockedProblematic = mockConstruction(Problematic.class, (mock, context) -> {
            // Now what?
            System.out.println("Context arguments: " + context.arguments());
        })) {
            MyClass.myCode();
        }
    }
}

如何拦截和/或模拟Problematic的构造函数,但仅当它被MyClass调用时?
这是对遗留代码的增量重构的一部分,我想在开始实际重构之前编写“固定测试”。

5anewei6

5anewei61#

有些重构比其他重构更不容易引起问题。在这种情况下,我建议重构类,以便可以控制有问题的类的构造。

class MyClass {
    // visible for testing
    static Function<String, Problematic> problematicFactory = Problematic::new;

    public static void myCode() {
        ThirdPartyLibrary.thirdPartyCode();
        problematicFactory.apply("this needs to be mocked");
    }
}

验证这不会改变类的行为应该是很简单的(您可以启动应用程序一次,然后验证它仍然可以工作-或者您相信这样的最小更改不会导致问题)。
然后在你的测试中,你可以把结构改为其他的:

class MockProblematicObjectConstructionTest {
    @Test
    void test() {
        MyClass.problematicFactory = arg => {
          throw new RuntimeException("whatever");
        };

        MyClass.myCode();
    }
}

最后,您可以将类转换为通过其构造函数使用依赖注入,并再次隐藏/封装字段。

相关问题