在Testbase
类中,它像这样自定义MyClass
fixture.Customize<MyClass>(c => c.Without(r => r.Foo));
并且在Testbase
的子类中具有
fixture.Customize<MyClass>(c => c.Without(r => r.Bar));
问题是我想在MyClass
的创建过程中添加更多的自定义内容,但似乎最后一个获胜/取代了第一个,因此它仍然设置MyClass.Foo
。
那么,如何更新自定义而不是覆盖自定义?
答案 0 :(得分:1)
简短的答案是您不能这样做。 Customize<>
API始终会附加一个新的自定义项,因此前一个是被覆盖的-这是设计使然。
作为一种可能的解决方法,您可以使用一些不同的语法来省略单个属性:
fixture.Customizations.Add(
new Omitter(
new EqualRequestSpecification(
typeof(MyClass).GetProperty(nameof(MyClass.Foo)))));
这样,您可以追加自定义项并在以后扩展例外列表:
fixture.Customizations.Add(
new Omitter(
new EqualRequestSpecification(
typeof(MyClass).GetProperty(nameof(MyClass.Bar)))));
请注意,如果您具有继承,则此方法会影响整个类的层次结构。因此,如果省略BaseClass.Foo
,则还将在每个子类中省略Foo
属性。
答案 1 :(得分:0)
有可能,但据我所知,您必须编写自己的治具才能传递给ICustomization的Customize方法。
这是我制作的一个示例:https://github.com/LethargicDeveloper/Lift.AutoFixture
我创建了一个扩展方法“ Compose()”,该方法需要进行ICustomization。它将一个特殊的灯具注入到您定义的自定义类中,并在将所有自定义添加到原始灯具的“自定义”集合中之前将所有自定义组合。
下面是完成大部分工作的代码段。
灯具具有一个定制集合,其中包含将要应用的所有定制。 Customization集合是List
键在Customize
import (
"fmt"
"net/http"
"sync"
"time"
"golang.org/x/net/context"
)
func main() {
var wg sync.WaitGroup
wg.Add(10)
c := make(chan string, 100)
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
for i := 1; i <= 10; i++ {
go SendHttpRequest(ctx, c, &wg)
}
for v := range c {
fmt.Println(v)
}
wg.Wait()
}
func SendHttpRequest(ctx context.Context, c chan string, wg *sync.WaitGroup) {
//defer wg.Done()
client := http.Client{}
req, err := http.NewRequest("POST", "https://jsonplaceholder.typicode.com/posts/1", nil)
if err != nil {
panic(err)
}
req.WithContext(ctx)
res, _ := client.Do(req)
select {
case <-time.After(1 * time.Microsecond):
c <- res.Status
case <-ctx.Done():
c <- "599 ToLong"
}
if res != nil {
defer res.Body.Close()
}
//close(c)
defer wg.Done()
}
使用您的示例,您可以这样编写:
internal class ComposableCustomizationBuilder : IFixture
{
private readonly IFixture fixture;
public ComposableCustomizationBuilder(IFixture fixture)
{
this.fixture = fixture;
this.Builders = new Dictionary<Type, object>();
}
// most of the IFixture methods have been removed for brevity since they just return the this.fixture implementation.
internal Dictionary<Type, object> Builders { get; }
public IFixture Customize(ICustomization customization)
{
customization.Customize(this);
return this;
}
public void Customize<T>(Func<ICustomizationComposer<T>, ISpecimenBuilder> composerTransformation)
{
if (!this.Builders.TryGetValue(typeof(T), out object builder))
{
var specimenBuilder = composerTransformation(SpecimenBuilderNodeFactory.CreateComposer<T>().WithAutoProperties(true));
this.Builders.Add(typeof(T), new NodeComposer<T>(specimenBuilder));
return;
}
this.Builders[typeof(T)] = composerTransformation(builder as ICustomizationComposer<T>);
}
internal IFixture BuildFixture()
{
if (this.fixture is ComposableCustomizationBuilder)
{
return this;
}
foreach (var builder in this.Builders)
{
var specimenBuilder = builder.Value as ISpecimenBuilder;
this.fixture.Customizations.Add(specimenBuilder);
}
return this.fixture;
}
}