尝试对使用模拟 Task<TResult> 的方法进行单元测试时出现问题
Problem while trying to unit test a method that uses a mocked Task<TResult>
我正在尝试对使用 FCM.This 方法发送一些通知的方法进行单元测试,该方法需要一个批次列表,并且为每个批次创建一个 IBatchResponse 任务,其中 IBatchResponse 是我创建的接口,因此我可以模拟发送通知的实际服务的 return 类型。然后使用 Task.WhenAny() 我在任务完成时对其进行处理。
public static async Task<NotificationRes> SendPushNotifications(List<Batch> batches, INotificationService notificationService)
{
var notificationTasks = new List<Task<IBatchResponse>>();
try
{
foreach (var batch in batches)
{
notificationTasks.Add(notificationService.SendNotification(guardTokens, "android"));
}
while (notificationTasks.Count > 0)
{
var finishedTask = await Task.WhenAny(notificationTasks);
var taskIndex = notificationTasks.FindIndex(task => task == finishedTask);
notificationTasks.Remove(finishedTask);
var finishedTaskResult = await finishedTask;
for (int i = 0; i < finishedTaskResult.Responses.Count; i++)
{
....
}
}
catch (Exception)
{
throw;
}
}
这是我正在尝试的测试代码 make.I 模拟了发送通知的包装服务和 return 类型的 notificationService.SendNotification (IBatchResponse)。
[Test]
public async Task SendPushNotifications_test()
{
...
var batchSendResponses = new List<ISendResponse>();
....
var mockNotifService = new Mock<INotificationService>();
var mockBatchRes = new Mock<IBatchResponse>();
mockBatchRes.Setup(res => res.Responses).Returns(batchSendResponses);
var task = Task.FromResult(mockBatchRes.Object);
mockNotifService.Setup(ns => ns.SendNotification(new string[5] { "token1", "token2", "", "", "" }, "android")).Returns(task);
var notRes = await Utils.SendPushNotifications(batches, mockNotifService.Object);
}
问题是,如果存在 2 个批次,则 finishedTask 结果始终为 null,但如果我有 1 个批次,它 works.What 我是否遗漏了这里。
我发现了 mockNotifService.Setup()
方法中的问题。
mockNotifService.Setup(ns => ns.SendNotification(new string[5] { "token1", "token2", "", "", "" }, "android")).Returns(task);
目前在 ns.SendNotification()
我正在对参数进行硬编码,这似乎会影响返回的任务,或者它不会生成我在 .Returns()
中指定的任务并生成一个没有结果的空任务。所以我将其更改为:
mockNotifService.Setup(ns => ns.SendNotification(It.IsAny<string []>(), It.IsAny<string>())).Returns(Task.FromResult(mockBatchRes.Object));
测试通过。
我正在尝试对使用 FCM.This 方法发送一些通知的方法进行单元测试,该方法需要一个批次列表,并且为每个批次创建一个 IBatchResponse 任务,其中 IBatchResponse 是我创建的接口,因此我可以模拟发送通知的实际服务的 return 类型。然后使用 Task.WhenAny() 我在任务完成时对其进行处理。
public static async Task<NotificationRes> SendPushNotifications(List<Batch> batches, INotificationService notificationService)
{
var notificationTasks = new List<Task<IBatchResponse>>();
try
{
foreach (var batch in batches)
{
notificationTasks.Add(notificationService.SendNotification(guardTokens, "android"));
}
while (notificationTasks.Count > 0)
{
var finishedTask = await Task.WhenAny(notificationTasks);
var taskIndex = notificationTasks.FindIndex(task => task == finishedTask);
notificationTasks.Remove(finishedTask);
var finishedTaskResult = await finishedTask;
for (int i = 0; i < finishedTaskResult.Responses.Count; i++)
{
....
}
}
catch (Exception)
{
throw;
}
}
这是我正在尝试的测试代码 make.I 模拟了发送通知的包装服务和 return 类型的 notificationService.SendNotification (IBatchResponse)。
[Test]
public async Task SendPushNotifications_test()
{
...
var batchSendResponses = new List<ISendResponse>();
....
var mockNotifService = new Mock<INotificationService>();
var mockBatchRes = new Mock<IBatchResponse>();
mockBatchRes.Setup(res => res.Responses).Returns(batchSendResponses);
var task = Task.FromResult(mockBatchRes.Object);
mockNotifService.Setup(ns => ns.SendNotification(new string[5] { "token1", "token2", "", "", "" }, "android")).Returns(task);
var notRes = await Utils.SendPushNotifications(batches, mockNotifService.Object);
}
问题是,如果存在 2 个批次,则 finishedTask 结果始终为 null,但如果我有 1 个批次,它 works.What 我是否遗漏了这里。
我发现了 mockNotifService.Setup()
方法中的问题。
mockNotifService.Setup(ns => ns.SendNotification(new string[5] { "token1", "token2", "", "", "" }, "android")).Returns(task);
目前在 ns.SendNotification()
我正在对参数进行硬编码,这似乎会影响返回的任务,或者它不会生成我在 .Returns()
中指定的任务并生成一个没有结果的空任务。所以我将其更改为:
mockNotifService.Setup(ns => ns.SendNotification(It.IsAny<string []>(), It.IsAny<string>())).Returns(Task.FromResult(mockBatchRes.Object));
测试通过。