使用内部 JSON 构造函数在 AutoFixture 4.8.0 中创建 public 类型,带有许多构造函数参数
Creating public types in AutoFixture 4.8.0 using internal JSON constructors, with many constructor arguments
在 AutoFixture 4.8.0 中,除了使用 Fixture.Register
注册函数来创建仅公开 internal
构造函数的类型之外,是否有更好的替代方法?
在上下文中:
我正在开发 .net 标准 class 库以构建 API 供内部使用。我们不想公开 public 个构造函数,因此这些模型的所有构造函数都是 internal
。属性另外 public readonly
。这些 classes 将通过 Json 反序列化进行实例化,并且在这个特定的库中有一个模型具有 > 20 个属性需要考虑。作为奖励,我们希望尽可能使用 [AutoDataAttribute]。
即。是否有替代方法可以使用 AutoFixture 为内部 jsonconstructor 提供非复杂类型(也是内部)和 20 多个参数的混合?
[TestFixture]
public sealed class Tests
{
private Fixture _fixture;
[OneTimeSetUp]
public void OneTimeSetup()
{
_fixture = new Fixture();
_fixture.Register(() => new Vehicle(_fixture.Create<string>(), _fixture.Create<int>()));
_fixture.Register(
() => new Driver(_fixture.Create<string>(), _fixture.Create<int>(), _fixture.Create<Vehicle>()));
}
[Test]
public void CanCreateDriverWithVehicle()
{
Func<Driver> func = () => _fixture.Create<Driver>();
func.Should().NotThrow(); // Green
}
}
[PublicAPI]
public sealed class Driver
{
public readonly string Name;
public readonly int Age;
public Vehicle Vehicle;
[JsonConstructor]
internal Driver(string name, int age, Vehicle vehicle)
{
Name = name;
Age = age;
Vehicle = vehicle;
}
}
[PublicAPI]
public sealed class Vehicle
{
public readonly string Manufacturer;
public readonly int Miles;
[JsonConstructor]
internal Vehicle(string manufacturer, int miles)
{
Manufacturer = manufacturer;
Miles = miles;
}
}
默认情况下,AutoFixture 仅考虑 public 构造函数。它不会获取内部构造函数,即使它们可以从测试执行程序集中访问(甚至不确定是否有合理的技术可能性来检查它)。
您可以轻松定制您的夹具来支持它。从以下代码示例中获取灵感:
[Fact]
public void ShouldActivateTypesWithInternalConstructor()
{
var fixture = new Fixture();
fixture.ResidueCollectors.Add(
new Postprocessor(
new MethodInvoker(
new ModestInternalConstructorQuery()),
new AutoPropertiesCommand()
));
var result = fixture.Create<TypeWithInternalConstructor>();
Assert.NotEqual(0, result.Property);
}
public class ModestInternalConstructorQuery : IMethodQuery
{
public IEnumerable<IMethod> SelectMethods(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return from ci in type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
where ci.IsAssembly // Take internal constructors only
let parameters = ci.GetParameters()
where parameters.All(p => p.ParameterType != type)
orderby parameters.Length ascending
select new ConstructorMethod(ci) as IMethod;
}
}
public class TypeWithInternalConstructor
{
public int Property { get; }
internal TypeWithInternalConstructor(int property)
{
Property = property;
}
}
在 AutoFixture 4.8.0 中,除了使用 Fixture.Register
注册函数来创建仅公开 internal
构造函数的类型之外,是否有更好的替代方法?
在上下文中:
我正在开发 .net 标准 class 库以构建 API 供内部使用。我们不想公开 public 个构造函数,因此这些模型的所有构造函数都是 internal
。属性另外 public readonly
。这些 classes 将通过 Json 反序列化进行实例化,并且在这个特定的库中有一个模型具有 > 20 个属性需要考虑。作为奖励,我们希望尽可能使用 [AutoDataAttribute]。
即。是否有替代方法可以使用 AutoFixture 为内部 jsonconstructor 提供非复杂类型(也是内部)和 20 多个参数的混合?
[TestFixture]
public sealed class Tests
{
private Fixture _fixture;
[OneTimeSetUp]
public void OneTimeSetup()
{
_fixture = new Fixture();
_fixture.Register(() => new Vehicle(_fixture.Create<string>(), _fixture.Create<int>()));
_fixture.Register(
() => new Driver(_fixture.Create<string>(), _fixture.Create<int>(), _fixture.Create<Vehicle>()));
}
[Test]
public void CanCreateDriverWithVehicle()
{
Func<Driver> func = () => _fixture.Create<Driver>();
func.Should().NotThrow(); // Green
}
}
[PublicAPI]
public sealed class Driver
{
public readonly string Name;
public readonly int Age;
public Vehicle Vehicle;
[JsonConstructor]
internal Driver(string name, int age, Vehicle vehicle)
{
Name = name;
Age = age;
Vehicle = vehicle;
}
}
[PublicAPI]
public sealed class Vehicle
{
public readonly string Manufacturer;
public readonly int Miles;
[JsonConstructor]
internal Vehicle(string manufacturer, int miles)
{
Manufacturer = manufacturer;
Miles = miles;
}
}
默认情况下,AutoFixture 仅考虑 public 构造函数。它不会获取内部构造函数,即使它们可以从测试执行程序集中访问(甚至不确定是否有合理的技术可能性来检查它)。
您可以轻松定制您的夹具来支持它。从以下代码示例中获取灵感:
[Fact]
public void ShouldActivateTypesWithInternalConstructor()
{
var fixture = new Fixture();
fixture.ResidueCollectors.Add(
new Postprocessor(
new MethodInvoker(
new ModestInternalConstructorQuery()),
new AutoPropertiesCommand()
));
var result = fixture.Create<TypeWithInternalConstructor>();
Assert.NotEqual(0, result.Property);
}
public class ModestInternalConstructorQuery : IMethodQuery
{
public IEnumerable<IMethod> SelectMethods(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return from ci in type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
where ci.IsAssembly // Take internal constructors only
let parameters = ci.GetParameters()
where parameters.All(p => p.ParameterType != type)
orderby parameters.Length ascending
select new ConstructorMethod(ci) as IMethod;
}
}
public class TypeWithInternalConstructor
{
public int Property { get; }
internal TypeWithInternalConstructor(int property)
{
Property = property;
}
}