[英]Moq: Verify object in parameter null reference
我正在尝试 Moq 一个同步过程,但我遇到了一个特定部分的问题。
在我的方法中,我尝试最小起订量,我执行以下操作:
public class SyncManager
{
private IPubHttpClient _pubHttpClient;
private ILogService _logService;
private Ilogger _logger;
public SyncManager(IPubHttpClient pubClient, ILogService logService ILogger<SyncManager> logger)
{
_pubHttpClient = pubClient;
_logService = logService;
_logger = logger;
}
public async Task Sync()
{
var syncStatus = SyncStatus.Error;
// get logs
var logs = await _logService.GetLogs();
foreach (var log in logs)
{
if (!string.IsNullOrEmpty(log.CostCode))
syncStatus = await GetAndSendCost(log);
elseif
syncStatus = await GetAndSendSort(log);
}
}
private async Task<SyncStatus> GetAndSendCost(Log log)
{
var cost = new Cost
{
CostCode = log.CostCode,
CostName = log.Description,
Active = log.Active
};
await _pubHttpClient.Push(new EventModel { Cost = cost, MessageType = log.Type.GetDescription() });
return SyncStatus.Success;
}
private async Task<SyncStatus> GetAndSendSort(Log log)
{
var sort = new Sort
{
SortCode = log.SortCode,
SortName = log.Description,
Active = log.Active
};
await _pubHttpClient.Push(new EventModel { Sort = sort, MessageType = log.Type.GetDescription() });
return SyncStatus.Success;
}
}
public class Log
{
public long Id { get; set; }
public string SortCode { get; set; }
public string CostCode { get; set; }
public string Description { get; set; }
public string Active { get; set; }
public AuditType Type { get; set; }
}
public class EventModel
{
public Cost Cost { get; set; }
public Sort Sort { get; set; }
public string MessageType { get; set; }
}
public enum AuditType
{
[Description("CREATE")]
Create = 0,
[Description("UPDATE")]
Update = 1,
[Description("DELETE")]
Delete = 2
}
public static class EnumExtensions
{
public static string GetDescription(this Enum enumValue)
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<DescriptionAttribute>()?
.Description ?? string.Empty;
}
}
我设置的测试是这样的:
public class SyncManagerTests
{
public readonly Mock<IPubHttpClient> _pubClientMock = new();
public readonly Mock<ILogService> _logServiceMock = new();
[Fact]
public async Task Should_Sync()
{
var mockedCost = new Cost { Active = Status.Active, CostCode = "0000", CostName = "UNIT TEST" };
var mockedSort = new Sort { Active = Status.Active, SortCode = "0001", SortName = "UNIT TEST" };
var mockedLogs = new List<Log> {
new Log { CostCode = mockedCost.CostCode, Description = mockedCost.CostName, Active = mockedCost.Active, Id = 1 },
new Log { SortCode = mockedSort.SortCode, Description = mockedSort.CostName, Active = mockedSort.Active, Id = 2 },
};
_logServiceMock.Setup(s => s.GetLogs()).ReturnsAsync(mockedLogs).Verifiable();
_pubClientMock.Setup(p => p.Push(It.Is<EventModel>(x => x.Cost == mockedCost && x.MessageType == "CREATE"))).Returns(Task.CompletedTask).Verifiable();
var syncManager = new SyncManager(_pubClientMock.Object, _logServiceMock.Object, Mock.Of<ILogger<SyncManager>>());
await syncManager.Sync();
_pubClientMock.Verify(p => p.Push(It.Is<EventModel>(
x => x.Cost.CostName == mockedCost.CostName
&& x.Cost.CostCode == mockedCost.CostCode
&& x.Cost.Active == mockedCost.Active
&& x.MessageType == "CREATE")));
}
}
当我运行这个测试时,每段代码都被正确调用,并且在调试时我看到EventModel object
正在使用正确的值创建。
但是在我的测试中,当我调用_pubClientMock.Verify();
我得到一个System.NullReferenceException
:这里的x.Cost
似乎是 NULL。
知道为什么这个属性会是 NULL 或者我在这里做错了什么吗?
所以再次迭代,实际上调用.Sync()
并使用调试器单步执行代码可以完美地工作。 _pubClientMock.Verify
因NullReferenceException
而失败。
类似于已经提供的答案之一,我建议通过使用It.IsAny
来放松设置以避免引用相等问题。 这将允许测试用例流向完成。
至于 Verification 中的 null 引用错误,由于更新后的示例会出现其中一个事件模型的Cost
属性值为 null 的情况,因此在验证谓词时需要检查 null
[TestClass]
public class SyncManagerTests {
public readonly Mock<IPubHttpClient> _pubClientMock = new Mock<IPubHttpClient>();
public readonly Mock<ILogService> _logServiceMock = new Mock<ILogService>();
[Fact]
public async Task Should_Sync() {
var mockedCost = new Cost { Active = Status.Active, CostCode = "0000", CostName = "UNIT TEST" };
var mockedSort = new Sort { Active = Status.Active, SortCode = "0001", SortName = "UNIT TEST" };
var mockedLogs = new List<Log> {
new Log { CostCode = mockedCost.CostCode, Description = mockedCost.CostName, Active = mockedCost.Active, Id = 1 },
new Log { SortCode = mockedSort.SortCode, Description = mockedSort.SortName, Active = mockedSort.Active, Id = 2 },
};
_logServiceMock.Setup(s => s.GetLogs()).ReturnsAsync(mockedLogs);
_pubClientMock
.Setup(p => p.Push(It.IsAny<EventModel>())) //<-- NOTE THIS
.Returns(Task.CompletedTask);
var syncManager = new SyncManager(_pubClientMock.Object, _logServiceMock.Object, Mock.Of<ILogger<SyncManager>>());
await syncManager.Sync();
_pubClientMock.Verify(p => p.Push(It.Is<EventModel>(
x => x.Cost != null //<-- NOTE THE NULL CHECK
&& x.Cost.CostName == mockedCost.CostName
&& x.Cost.CostCode == mockedCost.CostCode
&& x.Cost.Active == mockedCost.Active
&& x.MessageType == "CREATE")));
}
}
您能否提供有关通过 GetAndSendCost() 传递的 Log 的更多详细信息,也许问题来自该部分,您可以使用 It.IsAny<EventModel>()
// Arrange
Mock<IPubHttpClient> _pubClientMock = new Mock<IPubHttpClient>();
_pubClientMock.Setup(p => p.Push(It.IsAny<EventModel>())).Returns(Task.CompletedTask).Verifiable();
var syncManager = new SyncManager(_pubClientMock.Object, Mock.Of<ILogger<SyncManager>>());
// Act
await syncManager.Sync();
// Assert
_pubClientMock.Verify(p => p.Push(It.Is<EventModel>(
x => x.Cost.CostName == mockedCost.CostName
&& x.Cost.CostCode == mockedCost.CostCode
&& x.Cost.Active == mockedCost.Active
&& x.MessageType == "CREATE")));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.