我在我们的工具中有两个案例,我在使用静态字段进行集成测试时遇到了一些困难。在应用中这些字段是没有问题的。在我的测试中,我基本上使用每种测试方法创建了一个新应用程序。当我在一次测试运行中运行这些时,你可以想象,会有一些问题。首先让我展示两个这样的案例。
案例一
class SomeClass
{
private static IService service;
public static void Initialize(IService service)
{
SomeClass.service = service;
}
public void DoSomthing()
{
service.Foo();
}
}
基本上这个类的对象会被大量创建。为了能够使用 IService
对象,它被存储为一个静态字段。
在我的测试中,这是一个问题,因为 IService
实际上是一个 IServiceProvider
并且在第一次测试中只检索一次服务。在第二个测试中使用第一个测试的服务。
在实际应用中只有一个IService
或IServiceProvider
。因此我们在这里没有问题。
案例二
abstract class BaseClass
{
private static readonly Lazy<SpecificClass> specificClass = new Lazy<SpecificClass>(() => new SpecificClass());
public static SpecificClass SpecificClass
{
get { return specificClass.Value; }
}
}
class SpecificClass : BaseClass
{
}
这对我的测试来说更加麻烦,因为即使我创建了一个全新的应用程序,当 SpecificClass
在第一次测试中使用时,它在第二次测试中是同一个对象。
在我的测试中,我这里有内存泄漏,因为 SpecificClass
有一个列表,它会记住第一个测试中的对象。随着每次测试,越来越多的对象被添加到列表中。
在实际应用程序中,列表仅在应用程序启动时填充一次。所以这里没有内存泄漏。
我知道,测试通常会显示设计缺陷,但我在这里看不到。我能想到的删除这些静态字段的唯一论据是,否则我的测试不起作用。
那么我现在的问题是,为什么在这些情况下使用静态字段被认为是错误的代码,或者不是?我不想知道这些案例的解决方案。除了“我无法正确测试它”之外,我只需要说明为什么需要更改代码。
最佳答案
这里的设计缺陷是一个组件决定了其依赖项的生命周期,这在实际应用程序中是很糟糕的,并且在编码测试时会让事情变得更难。
您需要的是使用支持依赖注入(inject)的控制反转容器,并让它通过配置注入(inject)依赖的生命周期来决定。
例如,在 Castle Windsor 中它将配置如下:
IWindsorContainer container = new WindsorContainer();
container.Register
(
Component.For<SomeClass>().LifeStyleTransient(),
Component.For<IService>().ImplementedBy<SomeService>().LifeStyleSingleton()
);
所以你决定 IService
通过配置是一个单例,但你的代码依赖于 SomeClass
的实例将被注入(inject)一个 实现的实例IService
.
Why is it bad for the actual application. I only need a justification why a change in the code is necessary.
没有简单的单元测试:如果不使用实例构造函数和/或属性,就不能使用自动依赖注入(inject)。这会使您的代码更难测试,因为简单的配置无法注入(inject)假而不是实际实现。
没有自动依赖注入(inject)。不能将不同的应用程序和服务配置为使用相同或不同的依赖接口(interface)实现,并且您将失去一个大特性:对象生命周期( transient 、单例、每个请求、每个线程)可以通过配置和你的代码不应该意识到这一点。
无单一职责原则。您的类是否负责决定其依赖项的生命周期,或者不是应该定义它的框架?
你在问题的评论中对 Jon Skeet 说:
@JonSkeet I know why they are bad for my tests. But that is no accepted argument as long as it works for the real application. That is why I want to find a different argument. –
软件质量与实际应用一样真实。如果开发高质量的软件对您来说不是一个可接受的论点,也许您需要追根溯源,找出为什么应用程序或服务必须是可测试的。
关于c# - 什么反对静态字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35645597/