为了账号安全,请及时绑定邮箱和手机立即绑定

可以在不调用构造函数的情况下创建一个类的实例进行测试吗?

可以在不调用构造函数的情况下创建一个类的实例进行测试吗?

慕侠2389804 2022-07-14 16:40:59
是否可以在不模拟或调用其构造函数的情况下实例化具有复杂构造函数的类?这将很有用,因为每次将新的依赖项添加到服务时,单元测试类都不需要更改。模拟服务通过创建类的新实现来解决问题,并覆盖空方法,但这不是实现的实例。这是一个问题,因为每当调用模拟服务中的方法时,都必须告诉 Mockito 调用真实方法。相反,服务的实际实现将是首选。例如:class ComplexService {    private Service service1;    private Service service2;    private Service service3;    private Service service4;    private Service service5;    ComplexConstructor(Service service1, Service service2, Service service3, Service service4, Service service5) {        this.service1 = service1;        this.service2 = service2;        this.service3 = service3;        this.service4 = service4;        this.service5 = service5;    }    boolean methodToTest() {        return service1.get();    }}在单元测试类中,是否可以在不必调用其构造函数的情况下实例化实现?public class ComplexConostructorTest {    private ComplexConstructor complexConstructor;    private Service serviceMock;    @Before    public void init() {        /*         Somehow create implementation of complexConstructor         without calling constructor         . . .          */        // Mock dependency        ReflectionTestUtils.setField(complexConstructor,                 "service1",                 serviceMock = Mockito.mock(Service.class));    }    @Test    public void service1Test() {        when(serviceMock.get())                .thenReturn(true);        assertTrue(complexConstructor.methodToTest());    }}编辑可以使用反射,我希望在 JUnit 或 Mockito 中有一个内置的方法来实现同样的事情。这是使用反射的方法。@Beforepublic void init() {    Constructor<?> constructor = ComplexConstructor.class.getConstructors()[0];    complexConstructor = (ComplexConstructor) constructor.newInstance(new Object[constructor.getParameterCount()]);    // Mock dependency    ReflectionTestUtils.setField(complexConstructor,            "service1",            serviceMock = Mockito.mock(Service.class));}
查看完整描述

4 回答

?
江户川乱折腾

TA贡献1851条经验 获得超5个赞

您可以创建辅助方法作为测试代码的一部分,例如一些具有描述性名称的工厂方法来构造对象。例如,make_default_ComplexService等等,就像您的测试需要的那样。然后测试可以使用这些方法,如果构造函数发生变化,在许多情况下您只需更新辅助方法而不是所有测试。这种方法足够通用,也可以将您的测试与剧烈变化区分开来,例如将“带参数的构造函数”方法转变为“具有大量设置器的非参数构造函数”方法。

这种方法将减少您的测试的维护工作,您仍将使用原始构造函数(因为它被工厂调用)而不是一些假构造函数,并且您的测试代码甚至可能比工厂的直接构造函数调用更具可读性方法的名称选择得很好。


查看完整回答
反对 回复 2022-07-14
?
噜噜哒

TA贡献1784条经验 获得超7个赞

据我所知,这是不可能的,但您可以简单地在您的类中添加一个更简单的构造函数并将其用于测试。另一方面,如果测试在与应用程序中的状态不同的状态下测试对象,我不确定这样的测试会有多好。



查看完整回答
反对 回复 2022-07-14
?
达令说

TA贡献1821条经验 获得超6个赞

你可以,但你可能不想:

ComplexConstructor partialMock =
    Mockito.mock(ComplexConstructor.class, CALLS_REAL_METHODS);

这个“部分模拟”实例不会调用其构造函数或字段初始值设定项,但对被测系统的所有调用都会调用该类的真实行为。(从技术上讲,该类也将具有其equalshashCode为 Mockito 的目的而被覆盖,并且该类将是 ComplexConstructor 的生成子类,而不是 ComplexConstructor 本身。)

通过这种方式,您可以与构造函数隔离,但由于您正在抑制被测类行为的任意子集,因此要准确确定您正在测试的内容要困难得多,以便确信系统可以正常工作,因为测试通过。这应该是您在测试中的主要目标,而使用部分模拟可能很难实现这一目标。同事或合作者可能会正确地观察到,您不应该出于这个原因模拟您的测试系统。

虽然我个人认为您需要更改单元测试以在需要时提供模拟并不是错误或意外的,但您可以创建一个与您的测试分开的工厂来提供 ComplexConstructor 的测试实例,或者考虑使用依赖注入框架自动为您的被测系统提供模拟。



查看完整回答
反对 回复 2022-07-14
?
慕姐4208626

TA贡献1852条经验 获得超7个赞

看起来你混淆了几个术语和概念。让我帮助您更好地理解它们。

这将很有用,因为每次将新的依赖项添加到服务时,单元测试类都不需要更改。

您的类有许多依赖项,这些依赖项是通过构造函数提供的。如果您正在编写单元测试,您的目标只是测试这个依赖类,所有依赖项都应该被模拟。这就是为什么它被称为单元测试。这意味着对于您的类的每个新依赖项,都应该通过添加新的模拟及其模拟行为来更新测试。

必须告诉 Mockito 调用真正的方法。相反,服务的实际实现将是首选。

考虑集成测试,在这种情况下,您只能模拟一些依赖项,而其他依赖项将按预期或“真实”工作,直到您模拟它们。但是,如果您只想避免支持测试,那么这不是正确的方法。

请不要试图通过反射从您的测试中破解您的测试类。这可能会导致错误的测试结果、浪费时间和整体失望 :) 像 PowerMock 和 JMockit 这样的模拟库提供了任何类型的 hack,比如你尝试自己实现的那些,而且通常太强大了。

拥有权利的同时也被赋予了重大的责任


查看完整回答
反对 回复 2022-07-14
  • 4 回答
  • 0 关注
  • 131 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信