在开始之前,我是AutoFixture的忠实粉丝,我仍然在学习如何使用该工具.所以感谢开发了Autofixture先生Ploeh和所有贡献者.
那么让我们从我的问题开始吧.
根据 AutoFixture/AutoMoq忽略注入实例/冻结模拟
上面链接的有趣部分是给出了这段代码
Mock<ISettings> settingsMock = new Mock<ISettings>();
settingsMock.Setup(s => s.Get(settingKey)).Returns(xmlString);
ISettings settings = settingsMock.Object;
fixture.Inject(settings);
Run Code Online (Sandbox Code Playgroud)
马克回答哪个可以重写
fixture.Freeze<Mock<ISettings>>()
.Setup(s => s.Get(settingKey)).Returns(xmlString);
Run Code Online (Sandbox Code Playgroud)
它看起来像一个语法糖,使用Freeze方法是一种在流畅的界面中编写模拟,配置和自动混合容器中的注入的方法.
在对网络进行一些研究之后,Freeze和Inject之间实际上存在功能差异.我发现了这个问题:https: //github.com/AutoFixture/AutoFixture/issues/59 ,它指出了 如何在AutoFixture中冻结空实例的答案
上面链接的作者描述了Freeze方法如下:
在内部,Freeze创建一个所请求类型的实例(例如IPayPalConfiguration)然后注入它,这样当你再次请求它时它将始终返回该实例
我明白我们这样做的时候
var customer = fixture.Freeze<Order>();
Run Code Online (Sandbox Code Playgroud)
每当我们的代码请求Order类型时,它将始终使用相同的Order实例.但是如果我在Freeze构造函数中指定我希望它使用特定的实例呢?
这是一个小代码示例:
[Fact]
public void MethodeName()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
fixture.Freeze<OrderLine>(new OrderLine("Foo"));
var order = fixture.Create<Order>();
}
public class Order
{
private readonly OrderLine _line;
public Order(OrderLine line)
{
_line = line;
}
}
public class OrderLine
{
private readonly string _name;
public OrderLine(string name)
{
_name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
OrderLine的名称不应该等于"Foo"而不是namefe48163a-d5a0-49a5-b349-7b11ba5f804b吗?Freeze方法的文档说:
<typeparam name="T">The type to freeze.</typeparam>
<param name="fixture">The fixture.</param>
<param name="seed">Any data that adds additional information when creating the anonymous object. Hypothetically, this value might be the value being frozen, but this is not likely.</param>
Run Code Online (Sandbox Code Playgroud)
为什么作者不确定何时返回该值?如果我在Freeze的构造函数中指定我的实例,我期望自动混合使用此实例?
然后
请注意,除非您已自定义执行此操作,否则不可能将其用作冻结值.如果您希望将特定值注入Fixture,则应使用该方法
好像我必须自定义种子参数.任何人都可以澄清吗?文档指出的解决方案是使用Inject方法.事实上,它适用于我的OrderLine代码示例.
我正在寻找你的帮助,以了解Freeze,Inject和Register之间的区别,根据源代码,它只是由Inject方法调用,但它需要一个lambda.
Mar*_*ann 44
注册和注入
曾几何时,没有Inject,没有Freeze; Register统治代码.
那时候,有一个Register过载定义:
public static void Register<T>(this IFixture fixture, T item)
Run Code Online (Sandbox Code Playgroud)
但是,它必须与这个近亲共享API:
public static void Register<T>(this IFixture fixture, Func<T> creator)
Run Code Online (Sandbox Code Playgroud)
AutoFixture的创造者认为这很好,但唉:用户感到困惑.最悲惨的是,用户可以写:
fixture.Register(() => universe.LightUp());
Run Code Online (Sandbox Code Playgroud)
但是也
fixture.Register(universe.LightUp);
Run Code Online (Sandbox Code Playgroud)
这意味着完全相同的事情,因为universe.LightUp是对方法的引用,因此匹配委托.
但是,该语法看起来像属性引用,因此如果LightUp是属性而不是方法,则编译器将选择第一个重载.
这引起了很多混乱,因此Register<T>(this IFixture fixture, T item)重载被重命名为Inject<T>(this IFixture fixture, T item).
冻结
冻结有不同的历史.很久以前,当我仍然以强制方式使用AutoFixture时,我注意到我反复编写这样的代码:
var foo = fixture.Create<Foo>();
fixture.Inject(foo);
Run Code Online (Sandbox Code Playgroud)
所以我认为这是一个概念并命名为Freeze.该Freeze方法只是这两行代码的简写.
我正在寻找你的帮助,以了解Freeze,Inject和Register之间的区别,根据源代码,它只是由Inject方法调用,但它需要一个lambda
一般来说,区分Inject和之间不应该太难Register,因为它们的签名不会发生碰撞.因此,如果您尝试使用这两种方法中的一种来完成目标,并且您的代码已编译,那么您可能选择了正确的版本.
Freeze如果不是OP中使用的过载,也会出现这种情况:
[EditorBrowsable(EditorBrowsableState.Never)]
public static T Freeze<T>(this IFixture fixture, T seed)
Run Code Online (Sandbox Code Playgroud)
请注意,这种重载确实存在EditorBrowsableState.Never,因为它总是让人感到困惑.然而,尽管如此,显然人们仍然发现超载,所以我认为它应该在AutoFixture 4中移动.它是存在的功能之一,因为它易于实现......
Nik*_*nis 14
Freeze,Inject和Register所有都是自定义创建算法.
使用Inject和Register您明确指定应以特定方式创建对象,在您的示例中通过new OrderLine("Foo")手动提供.
随着Freeze你没有指定如何对象应创建-你问AutoFixture为您提供一个实例.
最后,所有上述方法都使用相同的低级API:
fixture.Customize<T>(c => c.FromFactory(creator).OmitAutoProperties());
之所以fixture.Freeze<OrderLine>(new OrderLine("Foo"));不创建OrderLine具有指定种子值的实例,是因为默认情况下会忽略种子.
要支持特定类型的种子值,您可以创建SeedFavoringRelay<T>:
public class SeedFavoringRelay<T> : ISpecimenBuilder where T : class
{
public object Create(object request, ISpecimenContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var seededRequest = request as SeededRequest;
if (seededRequest == null || !seededRequest.Request.Equals(typeof(T)))
return new NoSpecimen(request);
var seed = seededRequest.Seed as T;
if (seed == null)
return new NoSpecimen(request);
return seed;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用它如下:
fixture.Customizations.Add(
new SeedFavoringRelay<OrderLine>());
fixture.Freeze<OrderLine>(new OrderLine("Foo"));
// -> Now fixture.Create<Order>() creates an Order with OrderLine's Name = "Foo".
Run Code Online (Sandbox Code Playgroud)