You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Moq编写C#更新联系人单元测试时遇空引用异常求助

问题分析:UpdateContact单元测试抛出NullReferenceException

我用Moq框架编写单元测试验证UpdateContact功能,运行测试时抛出NullReferenceException,推测是待修改对象的列表未被正确赋值。我对Moq和单元测试并不熟悉,最初配置Contact.Get方法返回测试数据,之后修改为配置Where(c => c.Id == contact.Id,null,null).FirstOrDefault()返回对应数据,但问题仍存在,想了解具体错误原因。

测试代码

[TestFixture]
public class UpdateContactTests
{
    private static readonly object[] TestValidContact =
    {
        new object[]
        {
            "Prueba", "nearlinx@gmail.com", "86456245",
            new LookUpItem()
            {
                LookUpItemId = Guid.NewGuid(), Category = "ContactType", CategoryId = 1, Value = "Bulling Contact"
            },
            new Company()
            {
                Id = Guid.NewGuid(), Name = "Company", Email = "company@gmail.com", WebSite = "company.com",
                Nda = false, Msa = false, Phone = "84876817"
            }
        }
    };

    [TestCaseSource(nameof(TestValidContact))]
    [Test]
    public void UpdateContact_ValidValues_UpdateContact(string name, string email, string phone, LookUpItem lookUpItem, Company company)
    {
        //arrange
        var id = Guid.NewGuid();
        var data =
            new[]
            {
                new Contact { Id = Guid.NewGuid(), Name = "Test1", Email = "nearlinx@gmail.com", Phone = "86456245",
                    ContactType = 
                        new LookUpItem()
                        {
                            LookUpItemId = Guid.NewGuid(), Category = "ContactType", CategoryId = 1, Value = "Bulling Contact"
                        },
                    Company = 
                        new Company()
                        {
                            Id = Guid.NewGuid(), Name = "Company", Email = "company@gmail.com", WebSite = "company.com",
                            Nda = false, Msa = false, Phone = "84876817"
                        }},
                new Contact { Id = id, Name = "Test2", Email = "nearlinx@gmail.com", Phone = "86456245",
                    ContactType =
                        new LookUpItem()
                        {
                            LookUpItemId = Guid.NewGuid(), Category = "ContactType", CategoryId = 1, Value = "Bulling Contact"
                        },
                    Company =
                        new Company()
                        {
                            Id = Guid.NewGuid(), Name = "Company", Email = "company@gmail.com", WebSite = "company.com",
                            Nda = false, Msa = false, Phone = "84876817"
                        }},
            };

        var contact = new Contact()
        {
            Id = id,
            Name = name,
            Email = email,
            Phone = phone,
            ContactType = lookUpItem,
            Company = company
        };

        var _unitOfWork = new Mock<IUnitOfWork>();
        // 最初的配置
        //_unitOfWork.Setup(mock => mock.Contact.Get(null, null, null)).Returns(data);
        // 修改后的配置
        _unitOfWork.Setup(mock => mock.Contact.Where(c => c.Id == contact.Id,null,null).FirstOrDefault()).Returns(() => data.Where(c => c.Id == contact.Id));
        _unitOfWork.Setup(mock => mock.Company.Get(null, null, null)).Returns(new List<Company>());
        _unitOfWork.Setup(mock => mock.LookUpItem.Get(null, null, null)).Returns(new List<LookUpItem>());
        var contactService = new ContactService(_unitOfWork.Object);

        //act
        contactService.UpdateContact(contact);

        //assert
        Assert.That(data.First(m => m.Id == id).Name, Is.EqualTo(contact.Name));
        _unitOfWork.Verify(mock => mock.Contact.Update(It.IsAny<Contact>()), Times.Once);
    }
}

错误原因解析

  1. Moq Setup匹配失败:你硬编码了Where方法的lambda表达式作为匹配条件,但Moq默认会严格匹配参数(包括lambda的引用实例),而ContactService实际调用时用的lambda和你Setup里的不是同一个,导致Setup不生效,返回null触发NullReferenceException。

  2. 返回值类型不匹配:data.Where(c => c.Id == contact.Id)返回的是IEnumerable<Contact>集合,但FirstOrDefault()预期返回单个Contact对象,类型不匹配,即使Setup命中也无法拿到正确对象。

  3. 断言逻辑错误:你直接断言本地data数组的对象属性被修改,但ContactService操作的是Moq模拟的仓储对象,不会影响你本地的data数组,这个断言本身不成立。

修正方案

1. 正确配置Moq的Where方法

用It.IsAny<>匹配参数,让Where方法能根据传入的过滤条件返回正确集合:

// 替换原来的Where Setup
_unitOfWork.Setup(mock => mock.Contact.Where(It.IsAny<Expression<Func<Contact, bool>>>(), null, null))
           .Returns<Expression<Func<Contact, bool>>, object, object>((filterExpr, _, __) => 
               data.Where(filterExpr.Compile())
           );

2. 优化断言逻辑

放弃修改本地data的断言,转而验证仓储的Update方法被正确调用且传入对象符合预期:

// 替换原来的Assert部分
_unitOfWork.Verify(mock => mock.Contact.Update(It.Is<Contact>(c => 
    c.Id == contact.Id &&
    c.Name == contact.Name &&
    c.Email == contact.Email &&
    c.Phone == contact.Phone
)), Times.Once);

3. 优先使用GetById方法(如果存在)

如果你的IContactRepository提供了GetById方法,直接Setup会更简单:

// 替换Where的Setup
_unitOfWork.Setup(mock => mock.Contact.GetById(contact.Id))
           .Returns(data.First(c => c.Id == contact.Id));

内容的提问来源于stack exchange,提问作者TK154

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 14:41:28