首页 > 解决方案 > 在测试控制器发布方法时,我如何模拟 MySql 数据库返回的主键

问题描述

我的 xunit 测试失败,因为在单元测试时数据库没有更新预期的 ID。如何模拟数据库创建的 id/主键?

[HttpPost]
public async Task<ActionResult<AccountReadDto>> CreateAccountAsync(AccountCreateDto createAccountDto)
{
    var account = _mapper.Map<Account>(createAccountDto); // Id is int equal to 0
    await _accountRepo.CreateAccountAsync(account); // repo calls db and updates Id with pk
    _accountRepo.SaveChanges();

    var accountReadDto = _mapper.Map<AccountReadDto>(account);
    return CreatedAtRoute(nameof(GetAccountByIdAsync), new { AccountId = accountReadDto.AccountId }, accountReadDto);
}

[Fact]
public async Task CreateAccountAsync_NewAccount_ReturnsAccountReadDto()
{
    var expectedAccount = CreateRandomAccount(); // has id
    var createDto = _mapperStub.Map<AccountCreateDto>(expectedAccount); // doesn't have id

    _repoStub
        .Setup(repo => repo.CreateAccountAsync(expectedAccount))
        .Returns(Task.CompletedTask);
    var controller = new AccountController(_repoStub.Object, _mapperStub);

    var actionResult = await controller.CreateAccountAsync(createDto);

    var result = (actionResult.Result as CreatedAtRouteResult).Value as AccountReadDto;
    result.Should().BeEquivalentTo(
        expectedAccount,
        options => options.ComparingByMembers<AccountReadDto>().ExcludingMissingMembers() // excluding login info
    );
}

标签: c#mysql.netmodel-view-controllermoq

解决方案


此代码不正确:

_repoStub
    .Setup(repo => repo.CreateAccountAsync(expectedAccount))

它的设置CreateAccountAsync仅适用于您将expectedAccount实例作为参数传递的情况。(映射后就不一样了)。用于It.IsAny<T>()配置方法以使用任何参数。然后用于Callback<T>(Action<T>)访问传递给模拟调用的参数:

_repoStub
    .Setup(repo => repo.CreateAccountAsync(It.IsAny<Account>()))
    .Callback<Account>(a => a.Id = expectedAccount.Id)
    .Returns(Task.CompletedTask);

在该代码中,您将CreateAccountAsync方法配置为返回Task.CompletedTask并将传入参数 id 修改为expectedAccount.Id.

Returns(Task.CompletedTask)可以省略。(这是默认行为)

有关的附加信息Callback<T>链接


推荐阅读