c# - Autofixture 使用静态延迟实例化创建对象
问题描述
我有一个正在尝试测试的服务类,但遇到了一些困难
此类具有私有构造函数,因此必须从返回 Lazy _singleton 值的静态 Instance 属性创建它。
public class MyService : IMyService
{
private static readonly Lazy<IMyService> _singleton = new Lazy<IMyService>(() => new MyService(new InjectedService()));
public static IPermissionService Instance = _singleton.Value;
private readonly IInjectedService _injectedService;
private MyService(IInjectedService injectedService) => _injectedService = injectedService;
// instance method I want to test
public void DoSomething()
{
}
}
我正在尝试使用 AutoFixture 和 AutoMoq 创建我的对象,使用 Create() 方法,但它一直抱怨我没有公共构造函数。如果我将此构造函数设置为 public,我仍然会收到一个似乎来自 Lazy func 的错误。
有人可以帮忙吗?我可能有不同类型的设计问题。我不知道它是否可以轻松修复。
编辑 1: 我没有任何 IoC 容器,因此我可以将我的服务注册为单例。我试图使用这种方法来模拟依赖服务的注入,这样我就可以用 mock 编写测试。
我已经取得了一些进展,但我也不确定我是否喜欢它......无论如何我会分享我所拥有的
public static class My
{
private static readonly Lazy<IMyService> _singleton = new Lazy<IMyService>(() => new MyService(new InjectedService()));
public static IPermissionService Service = _singleton.Value;
}
public class MyService : IMyService
{
private readonly IInjectedService _injectedService;
public MyService(IInjectedService injectedService) => _injectedService = injectedService;
// instance method I want to test
public void DoSomething()
{
}
}
通过这种方式,我可以使用 AutoFixture 构建我的类并冻结注入服务的模拟。
我可以这样使用静态类
My.Service.DoSomething();
在我的测试中
Fixture.Freeze<Mock<IInjectedService>>().Setup(...);
var service = Fixture.Create<MyService>();
service.DoSomething();
// assert my things
解决方案
它不像你可能喜欢的那样使用自动模拟容器,但是属性(混蛋)注入应该能让你到达那里。
根据访问要求,将静态属性标记为internal
可能会或可能不会对未来的读者有所帮助,但由于您可以快速进行更改,从而允许在单例模式之外创建实例类,因此您似乎可以接受它。
如果您添加一个静态属性,通过该属性可以注入依赖项,您可以更改单例初始化程序以使用其值(混蛋注入:如果有的话)。
public class MyService : IService
{
private static readonly Lazy<IService > _singleton = new Lazy<IService >(() => new
MyService(MyDependency ?? new BastardizedInjectable()));
public static IService Instance = _singleton.Value;
internal static IMyDependency MyDependency
{
get;
set;
}
private readonly IMyDependency _injectedService;
private MyService(IMyDependency injectedService) => _injectedService = injectedService;
// instance method I want to test
public void DoSomething()
{
var stuff = _injectedService.GetStuff();
}
}
使用此实现,您的测试应该能够执行以下操作:
fixture.Customize<MyService>(c => c.FromFactory(() => MyService.Instance));
var depMock = fixture.Freeze<Mock<IMyDependency>>();
MyService.MyDependency = depMock;
var sut = fixture.Create<MyService>();
混蛋注入通常被称为反模式,或者至少与SOLID中的D (依赖倒置)背道而驰。如果您确信可以依赖此属性从 comp-root 注入,那么您应该硬着头皮删除?? new BastardizedInjectable()
. 未来你会感谢你的。
推荐阅读
- qt - 将 CSS 主题应用于已编译的 Qt 程序
- excel - Sub中的excel上的VBA宏运行时错误'5'
- elasticsearch - 是否有适用于 ElasticSeach 6.4.3 的应用程序客户端(类似于 DBvear)
- apache - Ansible 在多个主机上但从不同的路径重新启动 apache
- javascript - 如何使用 React 更改 Material UI 表格单元格的宽度?
- file - 从 url 共享文件
- javascript - 大家好,我如何通过单击按钮在#Ausgabe 中打印
- python - Tkinter 从实时显示的被调用函数中获取状态消息
- java - 以下具有 2 个 for 循环的代码的时间复杂度是多少?
- spring-boot - jpa多对多搜索查询(不在子句中)