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

单元测试中AutoMapper映射JobViewModel至DataAccess.Domain.Lab.Job始终返回空值的问题排查

Fixing Null Mapper Result in Unit Test

Alright, let's figure out why your _mapper.Map call returns null in the unit test but works perfectly with Postman. The core issue is how you've configured your IMapper mock—right now, it's not set up to return anything when the Map method is called, so Moq defaults to returning null for reference types.

Let's Break Down the Problem

  1. Missing Map method setup: You've configured the mock to return a MapperConfiguration with your JobsProfile, but you never told it what to do when Map<DataAccess.Domain.Lab.Job>(JobViewModel) is invoked. Moq doesn't automatically use the configuration you provided—it only follows explicit setups you define.
  2. Unused mock variable: In your AddJob_AddSingleEntry test, you create var mapperMock = new Mock<IMapper>() but never use it, which is just extra noise.

Solution 1: Fix the Mock Setup

If you want to keep using a mock for IMapper, explicitly define the return value for the Map method. Update your test setup to tell the mock how to convert a JobViewModel to a Job:

public class JobTests
{
    private static Mock<IMapper> _mapper;
    public JobTests()
    {
        if (_mapper == null)
        {
            _mapper = new Mock<IMapper>();
            // Add this setup to handle the Map call
            _mapper.Setup(x => x.Map<DataAccess.Domain.Lab.Job>(It.IsAny<JobViewModel>()))
                   .Returns((JobViewModel vm) => 
                       new DataAccess.Domain.Lab.Job 
                       {
                           // Map properties from vm to Job here—match your JobsProfile logic
                           Id = vm.Id,
                           Name = vm.Name,
                           Notes = vm.Notes?.Select(note => new JobNote
                           {
                               // Map note properties as needed
                               Text = note.Text,
                               IsNew = note.IsNew
                           }).ToList(),
                           // Add all other required properties
                       });
        }
    }

    [Fact]
    public async Task AddJob_AddSingleEntry()
    {
        // Remove the unused mapperMock variable
        var data = JobData.AddFakeJobList();
        var mockSet = FakeDbSetup.GetMockDbSet<DataAccess.Domain.Lab.Job>(data);
        var mockContext = FakeDbSetup.GetMockDbContext();
        mockSet.Setup(x => x.AsNoTracking()).Returns(mockSet.Object);
        mockContext.Setup(c => c.Jobs).Returns(mockSet.Object);
        
        AddJobCommandHandler handler = new AddJobCommandHandler(mockContext.Object, _mapper.Object);
        JobViewModel vm= JobData.AddFakeJobList2();
        AddJobCommand command = new AddJobCommand(vm);
        
        var jobViewModelResult = await handler.Handle(command, new System.Threading.CancellationToken());
        Assert.NotNull(jobViewModelResult);
    }
}

Mocking IMapper can lead to discrepancies between your test and production code—you might forget to map a property in the mock, while the real JobsProfile has it covered. A better approach is to create a real IMapper instance using your actual configuration:

public class JobTests
{
    private static IMapper _mapper;
    public JobTests()
    {
        if (_mapper == null)
        {
            // Create a real mapper with your JobsProfile
            var config = new MapperConfiguration(cfg => 
            {
                cfg.AddProfile<JobsProfile>();
            });
            // Validate your mapping configuration to catch issues early
            config.AssertConfigurationIsValid();
            _mapper = config.CreateMapper();
        }
    }

    [Fact]
    public async Task AddJob_AddSingleEntry()
    {
        var data = JobData.AddFakeJobList();
        var mockSet = FakeDbSetup.GetMockDbSet<DataAccess.Domain.Lab.Job>(data);
        var mockContext = FakeDbSetup.GetMockDbContext();
        mockSet.Setup(x => x.AsNoTracking()).Returns(mockSet.Object);
        mockContext.Setup(c => c.Jobs).Returns(mockSet.Object);
        
        AddJobCommandHandler handler = new AddJobCommandHandler(mockContext.Object, _mapper.Object);
        JobViewModel vm= JobData.AddFakeJobList2();
        AddJobCommand command = new AddJobCommand(vm);
        
        var jobViewModelResult = await handler.Handle(command, new System.Threading.CancellationToken());
        Assert.NotNull(jobViewModelResult);
    }
}

This way, you're testing the exact same mapping logic that runs in production, so you can trust the test results more. The AssertConfigurationIsValid() call will also throw an error if your JobsProfile has missing or invalid mappings, helping you catch issues before they reach production.

Final Checks

  • Make sure your JobsProfile correctly defines the mapping from JobViewModel to DataAccess.Domain.Lab.Job—if that's missing, even the real mapper will fail.
  • Double-check that all required properties are being mapped (either explicitly in the profile or via AutoMapper's conventions).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:57:34