单元测试和依赖注入与深度嵌套的依赖 [英] Unit testing and dependency injection with deeply nested dependencies

查看:646
本文介绍了单元测试和依赖注入与深度嵌套的依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设一个传统的类和方法的结构如下图所示。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆