假设遗留类和方法结构如下
public class Foo
{
public void Frob(int a, int b)
{
if (a == 1)
{
if (b == 1)
{
// does something
}
else
{
if (b == 2)
{
Bar bar = new Bar();
bar.Blah(a, b);
}
}
}
else
{
// does something
}
}
}
public class Bar
{
public void Blah(int a, int b)
{
if (a == 0)
{
// does something
}
else
{
if (b == 0)
{
// does something
}
else
{
Baz baz = new Baz();
baz.Save(a, b);
}
}
}
}
public class Baz
{
public void Save(int a, int b)
{
// saves data to file, database, whatever
}
}
然后假设管理层发布了一项模糊的任务,要求对我们所做的每一项新事物(无论是添加的功能、修改的需求还是错误修复)执行单元测试。
我可能比较坚持字面解释,但我认为“单元测试”这个词是有一定含义的。例如,这并不意味着给定输入 1 和 2,单元测试Foo.Frob
仅当 1 和 2 保存到数据库时才会成功。根据我读到的内容,我相信它最终意味着基于 1 和 2 的输入,Frob
调用Bar.Blah
。无论是否Bar.Blah
做了应该做的事并不是我最关心的事情。如果我关心测试整个过程,我相信还有另一个术语,对吗?功能测试?场景测试?任何。如果我太严格了,请纠正我!
目前坚持我的严格解释,让我们假设我想尝试利用依赖注入,其中一个好处是我可以模拟我的类,这样我就可以,例如,not将我的测试数据保存到数据库或文件或任何情况下。在这种情况下,Foo.Frob
needs IBar
, IBar
needs IBaz
, IBaz
可能需要一个数据库。这些依赖项要注入到哪里?进入Foo
?或者确实Foo
只是需要IBar
, 进而Foo
负责创建一个实例IBaz
?
当您进入这样的嵌套结构时,您很快就会发现可能需要多个依赖项。执行此类注射的首选或可接受的方法是什么?
让我们从你的最后一个问题开始。依赖项在哪里注入:一种常见的方法是使用构造函数注入(如福勒描述的 http://martinfowler.com/articles/injection.html). So Foo
被注入IBar
在构造函数中。具体实施IBar
, Bar
依次有一个IBaz
注入到它的构造函数中。最后是IBaz
执行 (Baz
)有一个IDatabase
(或其他)注入。如果您使用 DI 框架,例如城堡计划 http://www.castleproject.org/,您只需要求 DI 容器解析一个实例Foo
为你。然后它将使用您配置的任何内容来确定哪个实现IBar
您正在使用。如果它确定您的实施IBar
is Bar
然后它将确定哪个实施IBaz
你正在使用等等
这种方法为您提供的是,您可以单独测试每个具体实现,并且只需检查它是否正确调用(模拟的)抽象。
对于您对过于僵化等问题的担忧,我唯一能说的是,在我看来,您选择了正确的道路。也就是说,当实施所有这些测试的实际成本对管理层来说显而易见时,他们可能会感到惊讶。
希望这可以帮助。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)