请解释自定义和注册之间的功能差异,何时使用另一个。下面的TestCustomize
示例失败,TestRegister
通过。我希望自定义脚本能正常工作。它用英语读给我:“在生成HttpClient时,在提供specimin之前使用后处理lambda”。
但我得到的是一个带有guid的http地址,显然是由AutoFixture生成的。
[Fact]
public void TestCustomize()
{
var fixture = new Fixture();
fixture.Customize<HttpClient>(c =>
{
//c.OmitAutoProperties(); makes no difference
c.Do(x => x.BaseAddress = new Uri("http://myval"));
return c;
});
var client = fixture.Create<HttpClient>();
Assert.Equal("http://myval/", client.BaseAddress.ToString());
}
[Fact]
public void TestRegister()
{
var fixture = new Fixture();
fixture.Register(() => new HttpClient
{
BaseAddress = new Uri("http://myval")
});
var client = fixture.Create<HttpClient>();
Assert.Equal("http://myval/", client.BaseAddress.ToString());
}
这与Customize
与Register
无关。事实上,如果你看看source code for Register
,你会发现它只是一种比Customize
更方便的方法。
问题在于使用Do
。如果你看看Do
的签名,你会发现它有这种类型:
IPostprocessComposer<T> Do(Action<T> action)
请注意,该方法返回一个值。在功能样式中,或者,如果您愿意,在Command-Query Separation之后,该方法不会改变定义它的实例,而是返回具有已更改行为的新对象。
当一个人写道:
c.Do(x => x.BaseAddress = new Uri("http://myval"));
一个用改变的行为立即丢弃返回值。在像F#或Haskell这样的语言中,如果编写这样的代码,就会得到一个编译时通知,告诉你要忽略函数调用的返回值,但C#不会这样做。
无论如何,AutoFixture的API被设计为fluent interfaces。目的是将方法调用链接在一起:
fixture.Customize<HttpClient>(c => c
.Without(x => x.BaseAddress)
.Do(x => x.BaseAddress = new Uri("http://myval")));
你仍然需要Without
(或者,如果你愿意,OmitAutoProperties
)来关闭默认的自动属性行为,否则,BaseAddress
将被自动属性功能覆盖。
此版本的测试通过:
[Fact]
public void TestCustomize()
{
var fixture = new Fixture();
fixture.Customize<HttpClient>(c => c
.Without(x => x.BaseAddress)
.Do(x => x.BaseAddress = new Uri("http://myval")));
var client = fixture.Create<HttpClient>();
Assert.Equal("http://myval/", client.BaseAddress.ToString());
}