是否可以通过将抽象类实例化为模拟对象来对其进行单元测试?

本文关键字:单元测试 对象 可以通过 抽象类 实例化 模拟 是否 | 更新日期: 2023-09-27 17:50:11

我注意到您可以通过将抽象类实例化为模拟对象来对其进行单元测试。因此,您可以模拟抽象属性和方法,同时能够测试实现的属性和方法。

但是,我习惯于区分用于测试的类和用于模拟/存根的注入依赖项。所以,在我新启蒙的早期阶段,我想知道这种测试方式是否有任何陷阱?对此有什么想法吗?

问候,Morten

是否可以通过将抽象类实例化为模拟对象来对其进行单元测试?

一个抽象类,要有任何值,都应该有可以实例化的具体子类。所以对它们进行单元测试,并通过它们隐式地测试基类。

如果它没有具体的子类,我想不出它存在的任何理由(也就是说,作为一个抽象类)。

一般来说,我更喜欢使用mock来设置要测试的类的环境,而不是实例化类本身。对我来说,这种区别使测试用例更清晰,并确保我总是测试类的实际功能。

当然,当主要问题是能够以某种方式编写单元测试以启用重构(如有效地使用遗留代码中所讨论的)时,我可以想到(使用遗留代码)的情况。作为这种情况下的临时解决方案,(几乎)什么都可以。但是,一旦单元测试开始工作,应该尽快对类进行适当的重构,使其干净和可测试(以及它的单元测试,使它们可维护)。

与其使用继承来组合两个类,不如看看是否可以使用组合。

所以不用这个:

abstract class PaySalary {
    payAmount(decimal money) {
        if (transferAmount(money)) {
            isPaid = true;
        }
    }
    abstract void transferAmount(decimal money);
}

这样做:

class PaySalary {
    public MoneyTransferrer;
    payAmount(decimal money) {
        if (MoneyTransferrer.transferAmount(money)) {
            isPaid = true;
        }
    }
}
通过这种方式,您不必在单元测试中继承该类,但是您可以简单地模拟moneytransferer。您还可以在不依赖基类的情况下测试moneytransferer。

如果在我测试的部分中没有具体的实现,我通常编写一个测试实现。在单元测试中,我所做的事情与类的用户所做的类似。如果他继承了我的类,我在测试中继承。

另一方面,我不会说使用模拟框架来创建实现是不好的。在我的例子中,我通常不工作,通常是因为我需要为那个类编写ORM映射文件,诸如此类。

是的,你将测试一个抽象类,就像你测试一个带有注入的接口一样。

如果您为ILog编写测试并注入它以使用MockLog进行测试,那么您将为LogBase(在本例中是一个抽象类)做同样的事情,并将其注入MockLog

abstract class不是interface,但是它们在开销上的使用是相同的。

抽象类根据定义是抽象的。不应该有任何东西来测试它是否真正抽象。