预期UnitTest的ModelState无效,但不是

时间:2018-08-04 14:58:41

标签: c# unit-testing asp.net-core-mvc nunit

我有一个.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)行会返回false,因为需要Name-然后我将基于此执行Asserts。但是结果是正确的,因此我们尝试插入银行。

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

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

根据docs

  

在每个控制器动作被调用之前进行模型验证

所以我相信问题在于我如何创建BanksController。我是否以错误的方式参加了此测试?我想知道我是否应该在测试中将ModelState设置为无效...?

1 个答案:

答案 0 :(得分:2)

属性是仅在运行时由框架识别的元数据,而在单元测试期间则无法识别,因为模型绑定程序实际上是在应用程序运行时识别它们的。

要更改状态,您将不得不运行集成测试,其中框架的必要部分可用以更新模型状态,

或手动更新模型状态,因为控制器中的模型绑定未运行(尽管将使用集成测试来执行模型绑定),因此测试执行时其行为与预期的一样。

[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);
}
  

不要尝试在单元测试中测试模型验证或模型绑定-只需在遇到特定的ModelState值时测试操作方法的行为即可。

引用Test controller logic in ASP.NET Core