UnitTest 预计 ModelState 无效,但事实并非如此

UnitTest is expected ModelState to be invalid but it isn't

我有一个 .NetCore MVC 项目,我正在尝试对我的控制器进行单元测试。

ViewModel (注意 [Required] 属性):

public class Bank : BaseObject
{
    [Required]
    [DisplayName("Bank")]
    public string Name { get; set; }
}

控制器操作:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Name")] Bank bank)
{
    if (ModelState.IsValid)
    {
        await _bankService.Insert(bank);
        return RedirectToAction(nameof(Index));
    }
    return View(bank);
}

单元测试:

[Test]
public async Task When_PostingCreateBankThatIsInvalid_ThenBankIsReturned()
{
    var bank = new Bank
    {
        //nothing set = invalid state - this is what we want
    };
    var controller = new BanksController(null);
    var response = await controller.Create(bank);
}

我预计 if (ModelState.IsValid) 到 return 行是假的,因为 Name 是必需的 - 然后我将基于此执行我的 Asserts。但结果为真,所以我们尝试插入一个银行。

我在这里做错了什么?我用 Google 搜索过,但只能找到与单元测试无关的答案。我以为 ModelState 支持 [Required] 属性?

如果我使用 UI 进行测试,我无法创建没有名称的银行 - 它甚至从未到达控制器(如预期的那样)。

根据 docs:

Model validation occurs prior to each controller action being invoked

所以我认为问题在于我如何创建 BanksController。我是否以错误的方式接近这个测试?我想知道我是否应该在测试中将 ModelState 设置为无效...?

属性是仅在 运行 时被框架识别的元数据,而不是在单元测试期间,因为当应用程序处于 运行 时它们实际上被模型绑定器读取。

要更改状态,您要么必须 运行 集成测试,其中框架的必要部分可用于更新模型状态,

或手动更新模型状态,因为模型绑定未在控制器中 运行ning(尽管集成测试将用于执行模型绑定),以便测试在执行时按预期运行。

[Test]
public async Task When_PostingCreateBankThatIsInvalid_ThenBankIsReturned() {
    //Arrange
    var bank = new Bank
    {
        //nothing set = invalid state - this is what we want
    };
    var controller = new BanksController(null);
    controller.ModelState.AddModelError("Name","Name required");

    //Act
    var response = await controller.Create(bank);

    //Assert
    response.Should().NotBeNull()
        .And.BeOfType<ViewResult>();

    var viewResult = response as ViewResult;
    viewResult.Model.Should().Be(model);
}

Don't try to test model validation or model binding in your unit tests - just test your action method's behavior when confronted with a particular ModelState value.

引用Test controller logic in ASP.NET Core