【发布时间】:2013-05-02 11:48:46
【问题描述】:
我使用 TDD 编写了一个类,其中包含一个方法(被测方法),该方法将一个简单的值对象作为参数 (range)。
代码:
被测方法如下所示:
public List<string> In(IRange range)
{
var result = new List<string>();
for (int i = range.From; i <= range.To; i++)
{
//...
}
return result;
}
此外,我有一个单元测试来验证我的测试方法:
[TestMethod]
public void In_SimpleNumbers_ReturnsNumbersAsList()
{
var range = CreateRange(1, 2);
var expected = new List<string>() { "1", "2" };
var result = fizzbuzz.In(range);
CollectionAssert.AreEqual(expected, result);
}
private IRange CreateRange(int from, int to)
{
return new Fakes.StubIRange()
{
FromGet = () => { return from; },
ToGet = () => { return to; }
};
}
问题:
我读过 Roy Osherove 关于单元测试的书(“单元测试的艺术”)。他在那里说
"外部依赖项(文件系统、时间、内存等)应该是 被存根替换”
external 依赖是什么意思?我的值对象(范围)是否也是应该伪造的外部依赖项?我应该伪造一个类的所有依赖项吗?
谁能给个建议
【问题讨论】:
-
这意味着您应该测试正在审查的进程,而不是文件系统/时间/内存。不要依赖依赖项的具体实现,因为它们可以改变。您在 Stubbing
IRange中是正确的,因为您正在尝试使用任何IRange而不仅仅是一个特定的实现来测试方法In。 -
IRange 的实现有多少?这是您引入的纯粹用于支持模拟的接口吗?
-
@Romoku 如果 IRange 的实现遵循 LSP,那么使用哪个实现来提供测试并不重要,并且使用一个具体的实现不会使测试无效。
-
你不能用
IEnumerable<int>替换那个IRange接口吗?您的In方法可以定义为In(IEnumerable<int> range),您可以使用fizzbuzz.In(Enumerable.Range(1, 2))调用它。 -
许多函数式语言允许您将这种记录类型视为可互换的元组。例如在 Nemerle 你可以说
def (min, max) = SomeRange(0, 100);然后方法签名将是fizzbuzz.In(range : int * int)允许你传入任何范围,或者只是一个元组
标签: c# unit-testing dependency-injection tdd