测试控制器 post 方法时如何模拟 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
    );
}

解决方法

此代码不正确:

_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> 的其他信息:link

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...