C# 单元测试工厂/服务定位器-静态类
最近,我看到了这个代码。由于我试图一次学习几件事,我对这段代码有问题,但不知道如何解决。我希望能够对这段代码进行单元测试C# 单元测试工厂/服务定位器-静态类,c#,unit-testing,moq,factory-pattern,service-locator,C#,Unit Testing,Moq,Factory Pattern,Service Locator,最近,我看到了这个代码。由于我试图一次学习几件事,我对这段代码有问题,但不知道如何解决。我希望能够对这段代码进行单元测试 public static class CarFactory { private static readonly IDictionary<string, Type> CarsRegistry = new Dictionary<string, Type>(); public static void Register<TCar>
public static class CarFactory
{
private static readonly IDictionary<string, Type> CarsRegistry = new Dictionary<string, Type>();
public static void Register<TCar>(string car) where TCar : CarBase, new()
{
if (!CarsRegistry.ContainsKey(car))
{
CarsRegistry.Add(car, typeof(TCar));
}
}
public static ICar Create(string car)
{
if (CarsRegistry.ContainsKey(car))
{
CarBase newCar = (CarBase)Activator.CreateInstance(CarsRegistry[car]);
return newCar;
}
throw new NotSupportedException($"Unknown '{car}'");
}
}
,GetRedCar()方法将很难测试,因为它使用CarFactory静态类,对于单元测试或外部客户端,GetRedCar()方法API中没有任何内容表明它依赖于此静态类
我想重构CarFactory类,以便像上面的CarConsumer类示例一样使用它的其他类可以正确测试。
我希望能够对这段代码进行单元测试
public static class CarFactory
{
private static readonly IDictionary<string, Type> CarsRegistry = new Dictionary<string, Type>();
public static void Register<TCar>(string car) where TCar : CarBase, new()
{
if (!CarsRegistry.ContainsKey(car))
{
CarsRegistry.Add(car, typeof(TCar));
}
}
public static ICar Create(string car)
{
if (CarsRegistry.ContainsKey(car))
{
CarBase newCar = (CarBase)Activator.CreateInstance(CarsRegistry[car]);
return newCar;
}
throw new NotSupportedException($"Unknown '{car}'");
}
}
有哪些特定的问题阻止您对这个类进行单元测试?它有两种方法,编写单元测试似乎非常简单
名字是CarFactory,但在我看来,这不像是一个工厂模式
我相信工厂模式是可行的
工厂方法模式是一种创建模式,它使用工厂方法来处理创建对象的问题,而不必指定要创建的对象的确切类
我传入了汽车的名称(因此我没有指定类型),它为我创建了类。差不多就是这样。这是一个很好的例子吗?在我看来不是,但我对它做得有多好的看法并没有改变它是什么
这并不意味着它不是服务定位器,但它肯定是一种工厂方法。
(老实说,它看起来不像一个服务定位器,因为它只提供一个服务)
Moq等框架中的单元测试
Moq不是一个单元测试框架。Moq是一个模拟框架。静态类不容易模仿。如果可以模拟它,那么可以使用需要模拟类的方法进行单元测试
静态类。。它们还隐藏了依赖关系
任何设计拙劣的东西都可以做任何事情。静态类的定义并不是为了隐藏任何东西
在这个例子中,我想说的是,这个静态类使您无法轻松地模拟它来对依赖于静态类方法的其他方法进行单元测试
我还想对这个类进行单元测试,并需要帮助使它可以使用Moq进行单元测试
同样,没有什么可以阻止您对这个类进行单元测试
public class CarFactoryTests
{
public class MoqCar : CarBase { }
public void Register_WithValidParameters_DoesNotThrowException
{
// Act
Assert.DoesNotThrow(() => CarFactory.Register<MoqCar>(
nameof(Register_WithValidParameters_DoesNotThrowException)));
}
public void Create_WithValidCar_DoesNotThrowException
{
CarFactory.Register<MoqCar>(
nameof(Create_WithValidParameters_DoesNotThrowException));
Assert.DoesNotThrow(() => CarFactory.Create(
nameof(Create_WithValidParameters_DoesNotThrowException));
}
// etc etc
}
测试此方法意味着您无法完全控制该方法,因为存在外部代码GetRedCar()
所依赖的。您不能在这里编写纯单元测试
这就是为什么必须将CarFactory转换为实例类。然后确保它对于您正在使用的任何DI框架都具有正确的生存期
public class CarConsumer
{
private ICarFactory _carFactory;
public CarConsumer(ICarFactory carFactory)
{
_carFactory = carFactory;
}
public void ICar GetRedCar()
{
var result = _carFactory.Create("Tesla");
result.Color = Color.Red;
return result;
}
}
现在我们可以MoqICarfactory
并针对GetRedCar()
编写纯单元测试
以下是不推荐的
如果出于任何原因,您一直使用这种类型的工厂,但仍然希望编写纯单元测试,您可以执行以下操作:
public class CarConsumer
{
private Func<string, ICar> _createCar;
public CarConsumer(Func<string, ICar> createCar= CarFactory.Create)
{
_createCar = createCar;
}
public void ICar GetRedCar()
{
var result = _createCar("Tesla");
result.Color = Color.Red;
return result;
}
}
公共类汽车消费者
{
私家车;
公共汽车消费者(Func createCar=CarFactory.Create)
{
_createCar=createCar;
}
公共无效ICar GetRedCar()
{
var结果=_createCar(“特斯拉”);
结果.颜色=颜色.红色;
返回结果;
}
}
我们可以禁止这种类型的函数,但它实际上只是解决实际问题的一根拐杖
我想我真正的问题是如何制作我的CarFactory,以便使用它的其他类的方法可以使用Moq进行测试
公共接口ICarFactory
{
无效寄存器(字符串车),其中TCar:CarBase,new();
ICar创建(字符串车);
}
公共级汽车工厂:ICarFactory
{
专用只读IDictionary Cars注册表
=新字典();
公共无效登记簿(字符串车),其中TCar:CarBase,new()
{
如果(!CarsRegistry.ContainsKey(汽车))
{
添加(car,类型(TCar));
}
}
公共ICar创建(字符串车)
{
if(汽车登记箱(汽车))
{
CarBase newCar=(CarBase)Activator.CreateInstance(CarsRegistry[car]);
归还新车;
}
抛出新的NotSupportedException($“未知”{car}');
}
}
我希望能够对这段代码进行单元测试
public static class CarFactory
{
private static readonly IDictionary<string, Type> CarsRegistry = new Dictionary<string, Type>();
public static void Register<TCar>(string car) where TCar : CarBase, new()
{
if (!CarsRegistry.ContainsKey(car))
{
CarsRegistry.Add(car, typeof(TCar));
}
}
public static ICar Create(string car)
{
if (CarsRegistry.ContainsKey(car))
{
CarBase newCar = (CarBase)Activator.CreateInstance(CarsRegistry[car]);
return newCar;
}
throw new NotSupportedException($"Unknown '{car}'");
}
}
有哪些特定的问题阻止您对这个类进行单元测试?它有两种方法,编写单元测试似乎非常简单
名字是CarFactory,但在我看来,这不像是一个工厂模式
我相信工厂模式是可行的
工厂方法模式是一种创建模式,它使用工厂方法来处理创建对象的问题,而不必指定要创建的对象的确切类
我传入了汽车的名称(因此我没有指定类型),它为我创建了类。差不多就是这样。这是一个很好的例子吗?在我看来不是,但我对它做得有多好的看法并没有改变它是什么
这并不意味着它不是服务定位器,但它肯定是一种工厂方法。
(老实说,它看起来不像一个服务定位器,因为它只提供一个服务)
Moq等框架中的单元测试
Moq不是一个单元测试框架。Moq是一个模拟框架。静态类不容易模仿。如果可以模拟它,那么可以使用需要模拟类的方法进行单元测试
静态类。。它们还隐藏了依赖关系
任何设计拙劣的东西都可以做任何事情。静态类的定义并不是为了隐藏任何东西
在这个例子中,我想说的是,这个静态类使您无法轻松地模拟它来对依赖于静态类方法的其他方法进行单元测试
我还想对这个类进行单元测试,并需要帮助使它可以使用Moq进行单元测试
同样,没有什么可以阻止您对这个类进行单元测试
public class CarFactoryTests
{
public class MoqCar : CarBase { }
public void Register_WithValidParameters_DoesNotThrowException
{
// Act
Assert.DoesNotThrow(() => CarFactory.Register<MoqCar>(
nameof(Register_WithValidParameters_DoesNotThrowException)));
}
public void Create_WithValidCar_DoesNotThrowException
{
CarFactory.Register<MoqCar>(
nameof(Create_WithValidParameters_DoesNotThrowException));
Assert.DoesNotThrow(() => CarFactory.Create(
nameof(Create_WithValidParameters_DoesNotThrowException));
}
// etc etc
}
测试此方法意味着您不能完全控制此方法,因为