如何使用 Autofixture 中的 RandomRangedNumberCustomization 来确保参数在一定范围内?
How do I use the RandomRangedNumberCustomization in Autofixture to ensure parameters are in a certain range?
我有一个 class 有两个参数,如图所示:
public double X { get; private set; }
public double Y { get; private set; }
public Point(double x, double y)
{
if (x > 90 || x < -90)
throw new ArgumentOutOfRangeException("latitude");
if (y > 180 || y < -180)
throw new ArgumentOutOfRangeException("longitude");
X = x;
Y = y;
}
构造函数中设置了相应的属性,所以我需要告诉AutoFixture创建一个Pointclass,参数在guard子句指定的范围内。我对 RandomRangedNumberCustomization class 的用法感到有点困惑。我做了以下事情:
var xRange = new RangedNumberRequest(typeof(double), -90.0, 90.0);
var yRange = new RangedNumberRequest(typeof (double), -180.0, 180.0);
var dummyContext = new DelegatingSpecimenContext();
var generator = new RandomRangedNumberGenerator();
var x = (double)generator.Create(latitudeRange, dummyContext);
var y = (double) generator.Create(longitudeRange, dummyContext);
这将在我的范围内生成数字,因此我可以创建一个点并输入这些生成的数字,但我在自定义方面遗漏了一些东西。任何帮助和/或指导将不胜感激。
谢谢!
应该有几种方法可以为此自定义 AutoFixture。 – 以下是其中一些:
有数据注释
public class Point
{
public double X { get; private set; }
public double Y { get; private set; }
public Point(
[Range( -90, 90)]double x,
[Range(-180, 180)]double y)
{
if (x > 90 || x < -90)
throw new ArgumentOutOfRangeException("latitude");
if (y > 180 || y < -180)
throw new ArgumentOutOfRangeException("longitude");
this.X = x;
this.Y = y;
}
}
[Fact]
public void CreatePointDoesNotThrow()
{
var fixture = new Fixture();
Assert.DoesNotThrow(() => fixture.Create<Point>()); // Passes.
}
带发电机
public class Point
{
public double X { get; private set; }
public double Y { get; private set; }
public Point(double x, double y)
{
if (x > 90 || x < -90)
throw new ArgumentOutOfRangeException("latitude");
if (y > 180 || y < -180)
throw new ArgumentOutOfRangeException("longitude");
this.X = x;
this.Y = y;
}
}
[Fact]
public void CreatePointDoesNotThrow()
{
var fixture = new Fixture();
var x = new Generator<int>(fixture).First(pt => pt > -90 && pt < 90);
var y = new Generator<int>(fixture).First(pt => pt > -180 && pt < 180);
fixture.Customize<Point>(c => c
.FromFactory(() => new Point(x, y)));
Assert.DoesNotThrow(() => fixture.Create<Point>()); // Passes.
}
除了 Nikos Baxevanis 建议的解决方案外,还有另一种选择。您可以实现一个始终以特定方式处理 Point
的 x
和 y
参数的约定:
public class PointCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new XBuilder());
fixture.Customizations.Add(new YBuilder());
}
private class XBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null ||
pi.Name != "x" ||
pi.Member.DeclaringType != typeof(Point))
return new NoSpecimen(request);
return context.Resolve(
new RangedNumberRequest(typeof(double), -90d, 90d));
}
}
private class YBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null ||
pi.Name != "y" ||
pi.Member.DeclaringType != typeof(Point))
return new NoSpecimen(request);
return context.Resolve(
new RangedNumberRequest(typeof(double), -180d, 180d));
}
}
}
(以上代码还有重构的空间)
给定 PointCustomization
,此测试通过:
[Fact]
public void CreatePointDoesNotThrow()
{
var fixture = new Fixture().Customize(new PointCustomization());
var e = Record.Exception(() => fixture.Create<Point>());
Assert.Null(e);
}
我有一个 class 有两个参数,如图所示:
public double X { get; private set; }
public double Y { get; private set; }
public Point(double x, double y)
{
if (x > 90 || x < -90)
throw new ArgumentOutOfRangeException("latitude");
if (y > 180 || y < -180)
throw new ArgumentOutOfRangeException("longitude");
X = x;
Y = y;
}
构造函数中设置了相应的属性,所以我需要告诉AutoFixture创建一个Pointclass,参数在guard子句指定的范围内。我对 RandomRangedNumberCustomization class 的用法感到有点困惑。我做了以下事情:
var xRange = new RangedNumberRequest(typeof(double), -90.0, 90.0);
var yRange = new RangedNumberRequest(typeof (double), -180.0, 180.0);
var dummyContext = new DelegatingSpecimenContext();
var generator = new RandomRangedNumberGenerator();
var x = (double)generator.Create(latitudeRange, dummyContext);
var y = (double) generator.Create(longitudeRange, dummyContext);
这将在我的范围内生成数字,因此我可以创建一个点并输入这些生成的数字,但我在自定义方面遗漏了一些东西。任何帮助和/或指导将不胜感激。
谢谢!
应该有几种方法可以为此自定义 AutoFixture。 – 以下是其中一些:
有数据注释
public class Point
{
public double X { get; private set; }
public double Y { get; private set; }
public Point(
[Range( -90, 90)]double x,
[Range(-180, 180)]double y)
{
if (x > 90 || x < -90)
throw new ArgumentOutOfRangeException("latitude");
if (y > 180 || y < -180)
throw new ArgumentOutOfRangeException("longitude");
this.X = x;
this.Y = y;
}
}
[Fact]
public void CreatePointDoesNotThrow()
{
var fixture = new Fixture();
Assert.DoesNotThrow(() => fixture.Create<Point>()); // Passes.
}
带发电机
public class Point
{
public double X { get; private set; }
public double Y { get; private set; }
public Point(double x, double y)
{
if (x > 90 || x < -90)
throw new ArgumentOutOfRangeException("latitude");
if (y > 180 || y < -180)
throw new ArgumentOutOfRangeException("longitude");
this.X = x;
this.Y = y;
}
}
[Fact]
public void CreatePointDoesNotThrow()
{
var fixture = new Fixture();
var x = new Generator<int>(fixture).First(pt => pt > -90 && pt < 90);
var y = new Generator<int>(fixture).First(pt => pt > -180 && pt < 180);
fixture.Customize<Point>(c => c
.FromFactory(() => new Point(x, y)));
Assert.DoesNotThrow(() => fixture.Create<Point>()); // Passes.
}
除了 Nikos Baxevanis 建议的解决方案外,还有另一种选择。您可以实现一个始终以特定方式处理 Point
的 x
和 y
参数的约定:
public class PointCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new XBuilder());
fixture.Customizations.Add(new YBuilder());
}
private class XBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null ||
pi.Name != "x" ||
pi.Member.DeclaringType != typeof(Point))
return new NoSpecimen(request);
return context.Resolve(
new RangedNumberRequest(typeof(double), -90d, 90d));
}
}
private class YBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null ||
pi.Name != "y" ||
pi.Member.DeclaringType != typeof(Point))
return new NoSpecimen(request);
return context.Resolve(
new RangedNumberRequest(typeof(double), -180d, 180d));
}
}
}
(以上代码还有重构的空间)
给定 PointCustomization
,此测试通过:
[Fact]
public void CreatePointDoesNotThrow()
{
var fixture = new Fixture().Customize(new PointCustomization());
var e = Record.Exception(() => fixture.Create<Point>());
Assert.Null(e);
}