【发布时间】:2011-04-12 08:20:53
【问题描述】:
我注意到您可以通过将抽象类实例化为模拟对象来对其进行单元测试。因此,您可以模拟抽象属性和方法,同时能够测试已实现的属性和方法。
但是,我习惯于区分要测试的类和注入的依赖项要模拟/存根。所以,在我新启蒙的早期阶段,我想知道这种测试方式是否有任何陷阱?对此有什么想法吗?
问候, 莫腾
【问题讨论】:
标签: c# unit-testing inheritance mocking abstract-class
我注意到您可以通过将抽象类实例化为模拟对象来对其进行单元测试。因此,您可以模拟抽象属性和方法,同时能够测试已实现的属性和方法。
但是,我习惯于区分要测试的类和注入的依赖项要模拟/存根。所以,在我新启蒙的早期阶段,我想知道这种测试方式是否有任何陷阱?对此有什么想法吗?
问候, 莫腾
【问题讨论】:
标签: c# unit-testing inheritance mocking abstract-class
一个具有任何价值的抽象类都应该有可以被实例化的具体子类。所以对它们进行单元测试,并通过它们隐式地测试基类。
如果它没有具体的子类,我想不出它应该存在的任何理由(即作为抽象类)。
一般来说,我更喜欢使用模拟来设置要测试的类的环境,而不是实例化类本身。这种区别 - 对我来说 - 使测试用例更加清晰,并确保我始终测试类的真正功能。
当然,我可以想到主要问题是能够以某种方式编写单元测试以启用重构(如Working Effectively with Legacy Code 中所述)的情况(使用遗留代码)。作为这种情况下的临时解决方案,(几乎)任何事情都会发生。但是,一旦单元测试开始工作,就应该尽快对类进行适当的重构,使其干净且可测试(以及它的单元测试,以使其可维护)。
【讨论】:
Abstract*)。
不要用继承来组合两个类,看看能不能用组合。
所以不要这样:
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;
}
}
}
这样,您不必在单元测试中继承类,但您可以简单地模拟 MoneyTransferrer。您也可以在不依赖基类的情况下测试 MoneyTransferrer。
【讨论】:
如果我正在测试的部分没有具体的实现,我通常会编写一个测试实现。在单元测试中,我做的事情与我的课程的用户类似。如果他继承了我的类,我在测试中继承。
另一方面,我不会说使用模拟框架来创建实现是不好的。在我的情况下,我通常不工作,通常是因为我需要为那个类和类似的东西编写 ORM 映射文件。
【讨论】:
是的,您将测试一个抽象类,就像使用注入测试一个接口一样。
如果您为ILog 编写一个测试并使用MockLog 将其注入进行测试,那么您将对LogBase(在此示例中是一个抽象类)执行相同的操作并使用MockLog 注入它只是相同的。
abstract class 不是interface,但它们在开销上的使用几乎相同。
【讨论】:
根据定义,abstract class 是抽象的。不应该有任何东西可以测试它是否真的是抽象的。
【讨论】: