C# 复合根需要单元测试吗?

C# 复合根需要单元测试吗?,c#,dependency-injection,compositionroot,C#,Dependency Injection,Compositionroot,我试图找到一个答案,但似乎没有直接讨论太多。我有一个我的应用程序的合成根,在那里我创建一个DI容器并在那里注册所有内容,然后解析获得所有依赖项的所需顶级类。由于这一切都是在内部发生的,所以很难对组合根进行单元测试。您可以使用虚拟方法、受保护的字段等等,但我不太喜欢为了能够进行单元测试而引入这些东西。其他类没有什么大问题,因为它们都使用构造函数注入。所以问题是,测试作文的词根是否有意义?它确实有一些额外的逻辑,但不是很多,在大多数情况下,在应用程序启动期间会弹出任何故障。 我有一些代码: publ

我试图找到一个答案,但似乎没有直接讨论太多。我有一个我的应用程序的合成根,在那里我创建一个DI容器并在那里注册所有内容,然后解析获得所有依赖项的所需顶级类。由于这一切都是在内部发生的,所以很难对组合根进行单元测试。您可以使用虚拟方法、受保护的字段等等,但我不太喜欢为了能够进行单元测试而引入这些东西。其他类没有什么大问题,因为它们都使用构造函数注入。所以问题是,测试作文的词根是否有意义?它确实有一些额外的逻辑,但不是很多,在大多数情况下,在应用程序启动期间会弹出任何故障。 我有一些代码:

public void Initialize(/*Some configuration parameters here*/)
    {
        m_Container = new UnityContainer();

        /*Regestering dependencies*/

        m_Distributor = m_Container.Resolve<ISimpleFeedMessageDistributor>();
    }

    public void Start()
    {
        if (m_Distributor == null)
        {
            throw new ApplicationException("Initialize should be called before start");
        }

        m_Distributor.Start();
    }

    public void Close()
    {
        if (m_Distributor != null)
        {
            m_Distributor.Close();
        }
    }
public void Initialize(/*此处的一些配置参数*/)
{
m_Container=new UnityContainer();
/*重新酯化依赖*/
m_Distributor=m_Container.Resolve();
}
公开作废开始()
{
if(m_分配器==null)
{
抛出新的ApplicationException(“启动前应调用Initialize”);
}
m_Distributor.Start();
}
公众假期结束()
{
如果(m_分配器!=null)
{
m_分配器。关闭();
}
}
测试组合根是否有意义

您想知道您的应用程序编写是否正确吗?您可能会这样做,这就是您编写测试的原因。出于同样的原因,您应该测试您的作文根

然而,这些测试专门针对系统接线的正确性。您不想测试单个类是否正常工作,因为某些单元测试已经涵盖了这一点。您也不想测试类是否以正确的顺序调用其他类,因为这正是您想在常规集成测试中测试的(调用MVC控制器,看看调用是否在数据库中结束,这就是此类集成测试的一个示例)

以下是一些您可能应该测试的内容:

  • 所有顶级类都可以解析。这可以避免您必须点击应用程序中的所有屏幕,以确定是否所有内容都正确连接
  • 组件只依赖于寿命相同或更长的服务。当组件依赖于另一个配置了较短生存期的组件时,该组件将“提升”该依赖的生存期,这通常会导致难以复制和修复的错误。检查此类问题很重要。这种类型的错误也称为生活方式不匹配或强制依赖
  • 对应用程序的正确性至关重要的装饰器和其他拦截机制得到了正确应用。例如,装饰器可以添加横切关注点,如事务处理、安全性和缓存,这些关注点必须以正确的顺序执行(例如,在查询缓存之前必须执行安全检查),但使用普通的集成测试很难测试这一点
然而,要做到这一点,你需要有一个

但请注意,他们也同意这一观点。然而,根据我的经验,验证配置的正确性是非常有价值的

因此,使用一些IoC容器测试这些东西可能会很有挑战性,而其他IoC容器则具有帮助您实现这一点的功能(但不幸的是,Unity缺少大部分这些功能)

有些容器甚至有某种可以调用的验证方法来验证配置。对于每个库,“验证”的含义不同。例如,Simple Injector(我是Simple Injector的首席开发人员)有一个
Verify
方法,该方法将简单地迭代所有注册,并对每个注册调用
GetInstance
,以确保可以创建每个实例。只要可能,我总是建议您在其合成根目录中调用
Verify
。例如,这并不总是可能的,因为当配置变大时,调用Verify可能会导致应用程序启动太慢。但是,这仍然是一个很好的起点,可以消除很多痛苦。如果需要很长时间,您始终可以将调用移动到自动测试

对于简单的喷油器,这只是一个开始。简单喷油器包含检查容器是否存在常见错误配置,如前面提到的“生活方式不匹配”


因此,您应该绝对希望进行测试,但我不确定是否将这些测试称为“单元测试”,尽管我设法独立运行这些测试(无需访问数据库或web服务)。

您希望在这里测试什么?组合根是应用程序平台的挂钩。你找不到一个简单的方法来模拟所有的基础架构代码。例如,你想测试即将到来的配置是否被正确解析,启动调用m_Distributor.Start()等等。所以我不确定这是否非常需要……您是否使用XML文件进行配置?能否将所有容器配置移动到installer(installer在Castle Windsor中,在Ninject中称为模块)类?我从来没有使用过Unity。我想我可以把它移到另一个类或其他什么,然后对它进行单元测试。是的,然后你需要解析所有在测试中充当入口点的类。这将防止运行时出现错误。这就是你想要实现的吗?很高兴看到有人分享这个观点。我发现,在过去一年左右的时间里,自从我开始在我的.NET项目中实践实际的TDD以来,仍然发生的绝大多数错误都发生在我的IoC设置中,因为我没有或不能很好地测试它们。我不会为没有公开配置或具有verif的容器测试CompositionRoot