根据上下文为抽象属性创建具体类型
本文关键字:创建 类型 属性 抽象 上下文 | 更新日期: 2023-09-27 18:19:34
我有以下类型层次结构:
public abstract class ResourceId
{
}
public class CarId : ResourceId
{
}
public class PlaneId: ResourceId
{
}
public interface IResource
{
ResourceId Id { get; set; }
}
public class Plane : IResource
{
public ResourceId Id { get; set; }
}
public class Car : IResource
{
public ResourceId Id { get; set; }
}
我希望AutoFixture在尝试创建飞机或汽车时创建"正确"类型的ResourceId。
我尝试使用:
_fixture.Customize<Plane>(composer =>
composer.With(h => h.Id, _fixture.Create<PlaneId>()));
当然,这会为每个实例创建相同的ID。我希望每个人都有一个唯一的ID。
最好的方法是什么?
有一种方法可以满足您的要求,但它需要已知的自定义API:Register
方法。
Register
的目的是允许用户为特定类型指定工厂函数。然后,AutoFixture将该类型对象的创建委托给函数。
Register
的一个显著特点是,它能够提供匿名对象,以便在需要时将其作为参数传递给工厂函数。它是通过一些过载来实现的。以下是几个例子:
Register<T>(Func<T> factory)
没有向工厂提供任何参数Register<T1, T>(Func<T1, T> factory)
提供一个T1
类型的参数来创建T
类型的对象Register<T1, T2, T>(Func<T1, T2, T> factory)
提供两个类型为T1
和T2
的参数来创建类型为T
的对象
现在,我们可以使用此功能自定义创建Car
和Plane
类型对象的方式,方法是将CarId
和PlanId
的匿名实例分配给它们的Id
属性:
[Fact]
public void Test()
{
var fixture = new Fixture();
fixture.Register<CarId, Car>(id =>
{
var resource = new Car { Id = id };
return resource;
});
fixture.Register<PlaneId, Plane>(id =>
{
var resource = new Plane { Id = id };
return resource;
});
Assert.NotSame(fixture.Create<Car>().Id, fixture.Create<Car>().Id);
Assert.NotSame(fixture.Create<Plane>().Id, fixture.Create<Plane>().Id);
}
此测试通过是因为传递给工厂函数的CarId
和PlanId
对象是由AutoFixture创建的,因此每次都不同。
这里有一个简单的方法来做你想做的事情:
[Fact]
public void HowToUseFixtureToCreatePlanesWithNewIds()
{
var fixture = new Fixture();
fixture.Customize<Plane>(c => c
.Without(p => p.Id)
.Do(p => p.Id = fixture.Create<PlaneId>()));
var planes = fixture.CreateMany<Plane>();
Assert.True(planes.Select(p => p.Id).Distinct().Count() > 1);
}
然而,如果我是你,我会认真考虑简化类层次结构。。。
您必须自定义每个类的创建算法,在本例中为Car
和Plane
,如以下通过测试所示:
[Fact]
public void Test()
{
var fixture = new Fixture();
fixture.Customize<Plane>(c => c
.With(x => x.Id, fixture.Create<PlaneId>()));
fixture.Customize<Car>(c => c
.With(x => x.Id, fixture.Create<CarId>()));
var plane = fixture.Create<Plane>();
var car = fixture.Create<Car>();
Assert.IsType<PlaneId>(plane.Id);
Assert.IsType<CarId>(car.Id);
}