繁体   English   中英

Moq:验证参数空引用中的对象

[英]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.VerifyNullReferenceException而失败。

类似于已经提供的答案之一,我建议通过使用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM