以下测试在 AutoFixture 3.51.0
成功,但在4.0.0-rc1
失败:
(即使在 master 的最新提交中: c856cd6
)
``` c#
[事实]
public void ShouldApplyCustomizationsFromBaseClass()
{
var fixture = new Fixture();
夹具.定制
var res = fixture.Create
Assert.Equal(0, res.Id);
}
[事实]
public void ShouldApplyCustomizationsFromInterface()
{
var fixture = new Fixture();
夹具.定制
var res = fixture.Create
Assert.Equal(0, res.Id);
}
公共接口 IInterface
{
int ID { 获取; 放; }
}
公共类基类
{
公共 int Id { 获取; 放; }
}
公共类 ImplClass : BaseClass, IInterface
{
}
``
谢谢你提出这个问题。 嗯,这是我们想要的变化,它是故意应用的。
以前我们遇到过一个问题,即自定义一个子类型可能会影响其他子类型。 例如:
```c#
class Base { public string Common { get; 放; } }
类 Child1:基础 { }
类 Child2:基础 { }
[事实]
公共无效确保CustomizationAreNotAffected()
{
var fixture = new Fixture();
夹具.定制
var result = fixture.Create<Child2>();
Assert.NotNull(result.Common);
}
In the v3 this test failed, causing a lot of confusion to people. As you might imagine, the scenarios were more complicated and it was very non-obvious why the particular members are not initialized.
For instance, the following code will not work, which again proves that API is not designed for that.
```c#
fixture.Customize<Base>(c => c.With(x => x.Common, "foo"));
因此,为了解决这个问题,我们改变了方法,现在一种类型的定制不能影响其他类型,即使它们属于同一继承行。 正如你在那个 PR 中看到的那样,它修复了一堆可用性问题并增加了更多的清晰度(而变化确实是破坏性的)。
如果您仍然想省略 base/interface 属性,您可以使用以下代码段:
```c#
私有类 SamePropertySpecification : IRequestSpecification
{
私有只读类型_declaringType;
私有只读字符串_name;
public SamePropertySpecification(Type declaringType, string name)
{
_declaringType = declaringType;
_name = name;
}
public bool IsSatisfiedBy(object request)
{
if (request is PropertyInfo pi)
{
return pi.DeclaringType == this._declaringType &&
pi.Name.Equals(this._name, StringComparison.Ordinal);
}
return false;
}
}
[事实]
public void TestBasePropertyOmitting()
{
var fixture = new Fixture();
fixture.Customizations.Add(new Omitter(new SamePropertySpecification(typeof(Base), nameof(Base.Common))));
var result = fixture.Create<Child1>();
Assert.Null(result.Common);
}
``
如果您经常需要该功能,您可以为fixture
创建自己的扩展方法。 但是,我会投票选择不要开箱即用的功能,因为它看起来非常混乱。
好吧,很高兴知道这是故意的。 我绝对同意它令人困惑,但如果可以明确应用它,这是一个很好的功能。 将尝试您的代码段(并且可能会制作扩展方法)。
顺便说一句:这是您要添加到重大更改列表中的内容吗? 可能会阻止被问到同样的问题。
对于所有自定义中的任何一个自定义,都无法选择加入旧行为,对吗?
这是您想添加到重大更改列表中的内容吗?
嗯,它在错误修复部分中提到。 这实际上并不是一个重大变化,因为以前的行为从未被声明为“功能”。 相反,这是一个不受欢迎的副作用,它终于被消除了 😉
对于所有自定义中的任何一个自定义,都无法选择加入旧行为,对吗?
不,我不相信这样的方法,因为我完全重新设计了该方法。
请测试代码段,如果有效 - 请随时关闭问题。 或者如果您有其他问题,请告诉我😃
我已经对它进行了调整,因此它也适用于接口并制作了一个扩展方法,以便它可以在“Fixture.Customize”中使用
@nphmuller对不起,我破坏了你整洁的代码,现在你需要生存😄 但是我相信你的牺牲是为了我们所有人的利益,所以你不会过分责备我们😅
完全没有责备。 完全理解你的推理,甚至同意。 对我来说简直糟透了😉
以后可能会深入研究这个问题,看看有没有更简洁的方法。 现在还好。
只是出于好奇 - 您真正的用例是什么? 因为我从来没有遇到过这种功能的需求。。通常,当我编写测试时,我只需要自定义特定类型,而不是配置基类或接口类型。 正在编写某种全局定制吗?
在这种情况下,我们使用 AutoFixture 作为 Entity Framework 集成测试的测试数据生成器。
我们有几个基本类型或接口供我们的实体使用,它们包含公共属性。 ID,租户 ID(和导航属性),诸如此类。
例如,这些属性之一是创建对象的用户。 这个属性对于大多数测试来说并不是那么有趣,如果它被生成,它将创建一个巨大的图(用户类也有许多导航属性),必须生成并插入到数据库中。 这会使测试变慢甚至在 db 级别失败,因为该对象不应该以这种方式插入。
因此,在必要时简单地排除这些属性并选择加入会更容易。 在基类级别,因为否则必须为每个实体类型编写相同的省略规则。
@nphmuller感谢您的澄清,现在很清楚😉 是的,看起来这个场景是有道理的,但我必须承认它看起来像你很少需要的东西。