当我试图对一个服务方法进行单元测试时,它所实现的基本抽象类构造函数包含了2个参数。我想在使用Auto-fixture调用服务时自定义这些参数。
基本服务代码如下。
public abstract class ServiceBase : IHostedService, IDisposable
{
private readonly CronExpression _expression;
private readonly TimeZoneInfo _timeZoneInfo;
protected BaseService(string cronExpression, TimeZoneInfo timeZoneInfo)
{
_expression = CronExpression.Parse(cronExpression);
_timeZoneInfo = timeZoneInfo;
}
public abstract Task ExecuteTask(CancellationToken cancellationToken);
.
.
}
另一个服务从这个基础抽象类继承过来
public class TestService : ServiceBase
{
public override async Task ExecuteTask(CancellationToken stoppingToken)
{
//Implementation here
}
}
在我的单元测试中,我调用了 ExecuteTask
功能如下
Func<Task> executeAction = async () => await sut.ExecuteTask(A<CancellationToken>._);
executeAction.Should().NotThrow();
AutoFixture
试图将一个随机字符串传递给 CronExpression
构造参数 BaseService
类。问题是这样的 CronExpression
必须是特定的格式,否则在试图解析它时就会出现错误。CronExpression.Parse(cronExpression)
我如何为构造函数参数传递自定义值?
先谢谢你。
AutoFixture不知道服务的域约束。string
参数到你的类中。这应该给出一个提示,也许这个类型不是最合适的类的参数。这是一个典型的例子 原始的迷恋.
你可能会增强你的服务,而不是直接接受封装了这是一个CronExpression的想法的类型。
protected ServiceBase(CronExpression cronExpression, TimeZoneInfo timeZoneInfo)
{
_cronExpression = cronExpression;
...
}
这样一来,就能保证 BaseService
将通过一个有效的 CronExpression
. 如果不是这样,那就创造出了 CronExpression
将已经失败。
您可能会认为我们只是简单地转移了问题:您现在如何告诉 AutoFixture 创建一个有效的 CronExpression
?
将工作重心转移到建设的优势上。CronExpression
是,任何定制的创建一个有效的。CronExpression
现在 可重复使用 为任何其他需要的类型。这将减少未来任何最终需要该类型的测试的仪式。更不用说其他所有避免原始困扰的好处了。
关于告诉AutoFixture如何创建一个有效的 CronExpression
,有很多选择。你可以直接注入一个有效的。
fixture.Inject(CronExpression.Parse("myValidCronExpression"));
如果你希望能够选择多个,你可以用... ElementsBuilder
来从一个有效值池中选择。
public void Test()
{
var fixture = new Fixture();
fixture.Customizations.Add(new ElementsBuilder<CronExpression>(
new[] { "validExpr1", "validExpr2" }
.Select(s => CronExpression.Parse(s))
.ToArray()))
...
}
该类型的创建控制权最大的方式是创建一个实施方案。ISpecimenBuilder
我在这个回答中就不说了。如果你想走这条路,这里和其他地方都有很多例子。
在对AutoFixture进行定制后,你的SUT就可以工作了。
var sut = fixture.Create<TestService>();
注:我还没有测试过 TimeZoneInfo
可以直接被 AutoFixture 的默认样本构建器实例化。如果不能,也可以使用类似的方法来实现该类型。