单元测试和依赖注入与深度嵌套的依赖 [英] Unit testing and dependency injection with deeply nested dependencies
问题描述
假设一个传统的类和方法的结构如下图所示。
Assume a legacy class and method structure like below
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
}
}
然后承担管理问题含糊不清的任务执行单元测试,因为我们做的每一个新事物,是它的一个附加功能,修改要求或错误修复。
And then assume management issues a nebulous mandate to perform unit testing for every new thing we do, be it an added feature, modified requirement, or bug fix.
我可能是字面解释一个坚持己见的人,但我觉得那句单元测试意味着什么。这并不意味着,例如,1和2,鉴于输入, Foo.Frob
的单元测试应该会成功只有1和2都保存到数据库中。基于我读过,我相信这最终意味着基于对1和2输入, FROB
调用 Bar.Blah
。不管是不是 Bar.Blah
做了它应该做的是不是我杀到。如果我关心的测试整个过程中,我认为还有另一个术语,对吧?功能测试?场景测试?随你。纠正我,如果我太死板,请!
I may be a stickler for literal interpretation, but I think the phrase "unit testing" means something. It does not mean, for example, that given inputs of 1 and 2 that the unit test of Foo.Frob
should succeed only if 1 and 2 are saved to a database. Based on what I've read, I believe it ultimately means based on inputs of 1 and 2, Frob
invoked Bar.Blah
. Whether or not Bar.Blah
did what it is supposed to do is not my immediate concern. If I'm concerned with testing the entire process, I believe there's another term for that, right? Functional testing? Scenario testing? Whatever. Correct me if I'm being too rigid, please!
我的时刻严格解释坚持,让我们假设我想尝试使用依赖注入,有一个好处是,我可以嘲笑了我的班,这样我可以,例如,的不的坚持我的测试数据到数据库或文件或其他情况而定。在这种情况下, Foo.Frob
需要伊巴尔
,伊巴尔
需要 IBaz
, IBaz
可能需要一个数据库。凡在这些被注入?到富
?还是富
只需要伊巴尔
,然后富
是负责创建 IBaz
?
Sticking with my rigid interpretation for the moment, let's assume I want to try to utilize dependency injection, with one benefit being that I can mock away my classes so that I can, for example, not persist my test data to a database or file or whatever the case may be. In this case, Foo.Frob
needs IBar
, IBar
needs IBaz
, IBaz
may need a database. Where are these dependencies to be injected? Into Foo
? Or does Foo
merely need IBar
, and then Foo
is responsible for creating an instance of IBaz
?
当你进入一个嵌套的结构,例如,你可以快速看到有可能是必要的多个依赖。什么是执行这种注射的首选或接受的方法?
When you get into a nested structure such as this, you can quickly see there could be multiple dependencies necessary. What is the preferred or accepted method of performing such injection?
推荐答案
让我们从你的最后一个问题。在哪里注入的依赖关系:一种常见的方法是使用构造器注入(福勒描述为)。因此,富
注射用伊巴尔
在构造函数中。具体实施伊巴尔
,酒吧
依次有一个 IBaz
注入到它的构造。最后是 IBaz
实施(巴兹
)有一个了IDatabase
(或其他)注射。如果您使用的DI框架,如城堡项目,你会简单地问了DI容器来解决的一个实例富
为您服务。然后它会使用任何你已经配置,以确定哪些执行伊巴尔
你正在使用的。如果确定你的伊巴尔
的实施酒吧
然后将确定的实施 IBaz
您正在使用等。
Let us start with your last question. Where are the dependencies injected: A common approach is to use constructor injection (as described by Fowler). So Foo
is injected with an IBar
in the constructor. The concrete implementation of IBar
, Bar
in turn has an IBaz
injected into its constructor. And finally the IBaz
implementation (Baz
) has an IDatabase
(or whatever) injected. If you use a DI framework such as Castle Project, you would simply ask the DI container to resolve an instance of Foo
for you. It will then use whatever you have configured to determine which implementation of IBar
you are using. If it determines that your implementation of IBar
is Bar
it will then determine which implementation of IBaz
you are using, etc.
这是什么方法给你的,是你可以测试每个单独的具体实现,而只是检查它正确调用(嘲笑)的抽象。
What this approach gives you, is that you can test each of the concrete implementations in isolation, and just check that it invokes the (mocked) abstraction correctly.
要在你的担忧过于僵化等发表评论,我唯一能说的事情是,在我看来,你是选择正确的道路。也就是说,管理层可能会因为当实现所有这些测试的实际成本变得明显,他们都会感到惊讶。
To comment on your concerns about being too rigid etc, the only thing I can say is that in my opinion you are choosing the right path. That said, management might be in for a surprise when the actual cost of implementing all those tests becomes apparent to them.
希望这有助于。
这篇关于单元测试和依赖注入与深度嵌套的依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!