gpt4 book ai didi

unit-testing - 为什么 AutoFixture 自定义会导致未填充继承的属性?

转载 作者:行者123 更新时间:2023-12-04 12:10:07 28 4
gpt4 key购买 nike

我编写了以下自定义并将其作为组合的一部分应用于我的大多数测试。我的实体有一个只读 Id,但我在此自定义中使用它们的 SetId 方法来确保所有实体都有一些 Id,如果它们是 transient 的(还没有 Id)。

public class SetEntityIdCustomization : ICustomization {
public void Customize(IFixture fixture) {
var engine = ((Fixture)fixture).Engine;
fixture.Customizations.Add(new Postprocessor(
engine, o => {
var entity = o as BaseEntity;
if (entity == null || !entity.IsTransient()) {
return;
}
entity.SetId(fixture.CreateAnonymous<Guid>());
}));
}
}

这一直很有效,直到我今天发现了一件非常奇怪的事情。如果我提供一个直接从 BaseEntity 继承的实体的测试,一切都很好,并且它的可写属性是自动填充的。但是,如果我要求从 BaseEntity 更下方继承的实体,我的自定义会阻止属性自动填充。

此测试方法中的 User 实体已正确填充:
public class User : BaseEntity {
public string Email { get; set; }
public int CoolThings { get; set; }
}

...
[Theory, AutoDomainData]
public void SomeTest(User user, ...) {
// user.Email and user.CoolThings have auto-filled values, as expected.
...
}

但是,以下测试中的 AwesomeUser 实体不会自动填充任何相同的属性。
public class AwesomeUser : User {
...
}

...
[Theory, AutoDomainData]
public void SomeOtherTest(AwesomeUser user, ...) {
// user.Email nor user.CoolThings have auto-filled values. What gives?
...
}

在这两个测试用例中,由于我的自定义,Id 属性是自动填充的。如果我删除我的自定义,SomeOtherTest 的 AwesomeUser 实例会自动填充其继承的属性。我必须假设我的自定义是把事情搞砸了。

有没有更好的方法让我的所有 BaseEntity 实例设置它们的 Id,或者 AutoFixture 还缺少其他什么?我首先,中间和最后应用了我的自定义,但无济于事。

最佳答案

上面提供的解决方案是一个非常聪明的尝试,但不是我以前见过的。一个更惯用的解决方案是这样的:

public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new FilteringSpecimenBuilder(
new Postprocessor(
new BaseEntityBuilder(
new ConstructorInvoker(
new ModestConstructorQuery())),
new AutoPropertiesCommand().Execute),
new BaseEntitySpecification()));
}

private class BaseEntityBuilder : ISpecimenBuilder
{
private readonly ISpecimenBuilder builder;
private readonly IRequestSpecification specification;

public BaseEntityBuilder(ISpecimenBuilder builder)
{
this.builder = builder;
this.specification = new BaseEntitySpecification();
}

public object Create(object request, ISpecimenContext context)
{
if (!this.specification.IsSatisfiedBy(request))
return new NoSpecimen(request);

var b = (BaseEntity)this.builder.Create(request, context);
b.SetId((Guid)context.Resolve(typeof(Guid)));
return b;
}
}

private class BaseEntitySpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
var t = request as Type;
if (t == null)
return false;

if (!typeof(BaseEntity).IsAssignableFrom(t))
return false;

return true;
}
}

正如您所看到的,这不是一个简单的单行代码,这表明 AutoFixture 是一个相当固执的库。在这种情况下,AutoFixture 的意见是:

Favor object composition over class inheritance.

-Design Patterns, p. 20



AutoFixture 首先是一个 TDD 工具,TDD 的主要优点之一是它提供有关类设计的反馈。在这种情况下,反馈是:继承很尴尬,很麻烦。重新考虑设计。

关于unit-testing - 为什么 AutoFixture 自定义会导致未填充继承的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14639018/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com