背景
此代码在连接到GPS设备的小型RaspberryPi上运行。 GPS设备将GPS数据(纬度和经度)发送到RaspberryPi,RaspberryPi又将该数据发送到Amazon Web Services(云)上的服务。它适用于汽车远程信息处理。
问题
我希望编写一个集成测试,以确保当云的PostAsync
失败时,通过记录器记录某些内容。我的代码如下所示:
private void PostMovementToCloud(TelematicsAppEvent telemetryEvent)
{
var messageContent = new StringContent(JsonConvert.SerializeObject(telemetryEvent));
messageContent.Headers.ContentType = MediaTypeJson;
var result = _webClient.Value.PostAsync(GetEventEndPoint(telemetryEvent), messageContent, CancellationToken);
result.ContinueWith(t => { ContinuationSteps(t, result); });
}
private void ContinuationSteps(Task<HttpResponseMessage> t, Task<HttpResponseMessage> result)
{
if (t.IsFaulted || !result.IsCompletedSuccessfully)
{
// want to ensure this runs when the post to the cloud fails
_logger.LogError(EventHttpClientError, () => $"Unable to post telemetry: {reason}");
}
}
来自GPS的阅读速度快且频繁,我不想为每个.Wait()
执行PostAsync
,因为这会快速减慢/崩溃RaspberryPi。相反,我想在不等待响应的情况下发出请求。
但是,当我这样做时,如何在集成测试中测试ContinuationSteps
中的代码确实在运行?
集成测试代码
[TestFixture]
public class MyTest
{
private GpsSubscriberToJourneyEndPoint _gpsSubscriber;
private readonly Mock<ITopicConsumer> _kafkaTopicConsumerMock = new Mock<ITopicConsumer>();
[SetUp]
public void RunBeforeAnyTests()
{
var gpsSubscriberToJourneyEndPointOptions = new GpsSubscriberToJourneyEndPointOptions
{
StartEndPoint = "journey-start-point-url",
TimedEndPoint = "journey-mid-point-url",
StopEndPoint = "journey-end-point-url"
};
var gpsSubscriberToJourneyEndPointOptionsMock = new Mock<IOptions<GpsSubscriberToJourneyEndPointOptions>>();
var topicConsumerFactoryMock = new Mock<ITopicConsumerFactory>();
var loggerMock = new Mock<ICharlesLogger>();
var charlesLoggerFactoryMock = new Mock<ICharlesLoggerFactory>();
gpsSubscriberToJourneyEndPointOptionsMock
.SetupGet(o => o.Value)
.Returns(gpsSubscriberToJourneyEndPointOptions);
charlesLoggerFactoryMock
.Setup(cl => cl.CreateLogger(It.IsAny<Type>()))
.Returns(loggerMock.Object);
topicConsumerFactoryMock
.Setup(c => c.Create(It.IsAny<string>(), It.IsAny<IDictionary<string, string>>()))
.Returns(_kafkaTopicConsumerMock.Object);
_gpsSubscriber = new GpsSubscriberToJourneyEndPoint(
gpsSubscriberToJourneyEndPointOptionsMock.Object,
topicConsumerFactoryMock.Object, charlesLoggerFactoryMock.Object);
}
[Test]
public void CheckFailingPostAsync()
{
// first and second reading have to be different in Lat and Lng to move the State machine to 'car moving state'
const string firstGgaReading = "{\"Latitude\":53.639643,\"Longitude\":-1.782644,\"QualityIndicator\":2}";
const string secondGgaReading = "{\"Latitude\":53.639399,\"Longitude\":-1.782834,\"QualityIndicator\":4}";
_gpsSubscriber.Start(new CancellationToken());
// Act
// I'm raising the message received event here (message from gps device)
_kafkaTopicConsumerMock
.Raise(ktc => ktc.Message += null, new MessageEventArgs("Bam", firstGgaReading));
_kafkaTopicConsumerMock
.Raise(ktc => ktc.Message += null, new MessageEventArgs("Boom", secondGgaReading));
}
}
答案 0 :(得分:2)
我认为你无论如何都不应该创造一个即发即弃的任务。如果你创建了一个Task
并让它活着,那么它可能会在你最不期望的时候回来咬你,你将很难找到实际发生的事情。
最好是PostMovementToCloud
方法返回result
Task
实例。然后你可以在测试中等待它,你就可以正确地测试它。
hacky解决方案涉及人工等待(如Task.Delay
),然后检查结果。如果您正在测试失败的情况,您可能会使任务快速失败,因此任何小的延迟都应该足够。但正如我所说,这是hacky而不是一个好的解决方案。