从未设置单元测试中的配置值



我的C#应用程序有一个HealthHandler类,它在构造函数中使用config作为参数。

public class HealthHandler : IHeartbeatCheckHealthHandler
{
private readonly IApplicationTime _applicationTime;
private readonly IConfig _config;

private DateTime _time = DateTime.UtcNow;
private readonly TimeSpan _timespan;

public bool IsHealthy => (_time.Add(_timespan) > _applicationTime.UtcNow);

public HealthHandler([NotNull] IConfig healthcheckOptions)
{
_applicationTime = new StandardManualTimer(new DateTime?(DateTime.UtcNow));
_config = healthcheckOptions ?? throw new ArgumentNullException(nameof(healthcheckOptions));
_timespan = TimeSpan.FromSeconds(_config.HeartbeatTimespan);
}

public void OnMessage(int value)
{
if (value == 10)
{
_time = _applicationTime.UtcNow;
}
}
}

我正在尝试对此进行单元测试。到目前为止,我得到的是:

public class HealthcheckTest
{
private IConfig _config;

public HealthcheckTest()
{
_config = new FeedConfigOptions();
_config.HeartbeatTimespan = 5;
}

[Fact]
public void TestKafkaHealthStateUpdates()
{

HealthHandler healthHanler = new HealthHandler(_config);
healthHanler.OnMessage(2);
healthHanler.IsHealthy.Should().Be(true);
Thread.Sleep(6000);
healthHanler.IsHealthy.Should().Be(false);
healthHanler.OnMessage(10);
healthHanler.IsHealthy.Should().Be(true);
}

}

每个healthHanler.IsHealthy.Should().Be();调用都返回true。我的测试似乎从未将心跳时间跨度设置为5,它总是默认为0。

我的StandardManualTimer如下所示:

public class StandardManualTimer : ManualTimer<DateTime>, IApplicationTime
{
public StandardManualTimer(DateTime? initial = null, TimerGranularity? granularity = null)
: base(initial ?? DateTime.UtcNow, granularity)
{
}

public void AdvanceBy(TimeSpan timeSpan) => this.AdvanceTo(this.Now.Add(timeSpan));

public DateTime UtcNow => this.Now;
}

以下是手动定时器:

public class ManualTimer<TPriority> : IManualTimer<TPriority>, ITimer<TPriority>, IDisposable
where TPriority : IComparable<TPriority>
{
private volatile bool _isDisposed;

[NotNull]
public TPriority Next { get; private set; }

public TimerGranularity Granularity { get; }

[NotNull]
public TPriority Previous { get; private set; }

public bool IsCancelled { get; private set; }

public ManualTimer(TPriority initial, TimerGranularity? granularity = null)
{
this.Next = (object) initial != null ? initial : throw new ArgumentNullException(nameof (initial), "The initial time cannot be null");
this.Granularity = granularity.GetValueOrDefault();
this.Previous = initial;
this.Now = initial;
this.IsCancelled = true;
}

public void Dispose() => this._isDisposed = true;

public void Cancel() => this.IsCancelled = true;

public TimerChangeResponse RequestNext(TPriority next)
{
if (this._isDisposed)
return TimerChangeResponse.Disposed;
if (next.CompareTo(this.Now) <= 0)
return TimerChangeResponse.FailedRetry;
this.IsCancelled = false;
this.Next = next;
return TimerChangeResponse.Scheduled;
}

public void AdvanceTo(TPriority newNow)
{
if ((object) newNow == null)
throw new ArgumentNullException(nameof (newNow), "Now cannot be null");
if (this.Granularity == TimerGranularity.Fine)
{
while (!this.IsCancelled && this.Next.CompareTo(newNow) < 0 && this.Next.CompareTo(this.Previous) > 0)
SetNow(this.Next);
}
if (this.Now.CompareTo(newNow) >= 0)
return;
SetNow(newNow);

void SetNow(TPriority value)
{
this.Now = value;
if (this.IsCancelled || this.Now.CompareTo(this.Next) < 0 || this.Next.CompareTo(this.Previous) <= 0)
return;
this.Previous = value;
EventHandler nextFired = this.NextFired;
if (nextFired == null)
return;
nextFired((object) this, EventArgs.Empty);
}
}

public event EventHandler NextFired;

[NotNull]
public TPriority Now { get; private set; }
}

如何在测试中解决此问题?

_applicationTime用当前时间初始化:

_applicationTime = new StandardManualTimer(new DateTime?(DateTime.UtcNow));

_applicationTime.UtcNow返回初始化值,则Thread.Sleep不影响_applicationTime.UtcNow。你需要像一样使用_applicationTime.AdvanceTo

注入IApplicationTime:

public class HealthHandler : IHeartbeatCheckHealthHandler
{
private readonly IApplicationTime _applicationTime;
private readonly IConfig _config;
private DateTime _time = DateTime.UtcNow;
private readonly TimeSpan _timespan;
public bool IsHealthy => (_time.Add(_timespan) > _applicationTime.UtcNow);
public HealthHandler([NotNull] IConfig healthcheckOptions, IApplicationTime applicationTime)
{
_applicationTime = applicationTime;
_config = healthcheckOptions ?? throw new ArgumentNullException(nameof(healthcheckOptions));
_timespan = TimeSpan.FromSeconds(_config.HeartbeatTimespan);
}
public void OnMessage(int value)
{
if (value == 10)
{
_time = _applicationTime.UtcNow;
}
}
}

并修改测试:

[Fact]
public void TestKafkaHealthStateUpdates()
{
var app = new StandardManualTimer(DateTime.UtcNow);
HealthHandler healthHanler = new HealthHandler(_config, app);
healthHanler.OnMessage(2);
healthHanler.IsHealthy.Should().Be(true);
Thread.Sleep(6000);
app.AdvanceTo(DateTime.UtcNow);
healthHanler.IsHealthy.Should().Be(false);
healthHanler.OnMessage(10);
healthHanler.IsHealthy.Should().Be(true);
}

额外奖励:你还可以模拟IApplicationTime

最新更新