使用深层嵌套依赖项进行单元测试和依赖注入

Ant*_*ram 7 c# unit-testing dependency-injection

假设遗留类和方法结构如下所示

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
    }
}
Run Code Online (Sandbox Code Playgroud)

然后假设管理层发出一项模糊的任务,对我们所做的每件新事物执行单元测试,无论是增加的功能,修改的需求还是错误修复.

我可能是文字解释的坚持者,但我认为"单元测试"这个短语意味着什么.例如,这并不意味着给定1和2的输入,Foo.Frob只有当1和2保存到数据库时,单元测试应该成功.基于我所读到的内容,我认为它最终意味着基于1和2的输入,Frob被调用Bar.Blah.是否Bar.Blah做了应该做的事情不是我直接关注的问题.如果我关心测试整个过程,我相信还有另一个术语,对吗?功能测试?场景测试?随你.如果我太僵硬,请纠正我,拜托!

坚持我刚才的严格解释,让我们假设我想尝试利用依赖注入,一个好处是我可以模拟我的类,以便我可以,例如,我不能将我的测试数据保存到数据库或文件或无论情况如何.在这种情况下,Foo.Frob需求IBar,IBar需求IBaz,IBaz可能需要一个数据库.注入这些依赖项在哪里?进Foo?或Foo仅仅需要IBar,然后Foo负责创建一个实例IBaz

当您进入这样的嵌套结构时,您可以快速看到可能存在多个必需依赖项.进行这种注射的首选方法是什么?

Kla*_*sen 7

让我们从你的上一个问题开始.注入的依赖项在哪里:一种常见的方法是使用构造函数注入(如Fowler所述).所以在构造函数中Foo注入了一个IBar.具体实现的IBar,Bar反过来的IBaz注入它的构造.最后,IBazimplementation(Baz)有一个IDatabase(或其他)注入.如果您使用诸如Castle Project之类的DI框架,您只需要求DI容器Foo为您解析一个实例.然后,它将使用您配置的任何内容来确定IBar您正在使用的实现.如果它确定你的实现IBarBar然后它将确定IBaz您正在使用的实施,等等.

这种方法给你的是,你可以单独测试每个具体的实现,并检查它是否正确调用(模拟)抽象.

为了评论你对过于严格等问题的担忧,我唯一可以说的是,在我看来,你正在选择正确的道路.也就是说,当实施所有这些测试的实际成本变得明显时,管理层可能会感到意外.

希望这可以帮助.