AspNetCore 上的单元测试控制器模型验证

Unit test controller model validation on AspNetCore

在 ASPNET Core 项目中,我正在尝试创建一些单元测试来验证我的数据验证逻辑是否正常工作。

我的控制器很简单:

[HttpPost]
[Route("Track")]
public void Track([FromBody] DataItem item)
{
    if (!ModelState.IsValid) throw new ArgumentException("Bad request");

    _dataItemSaver.SaveData(item);
}

我正在使用一个测试基础 class,它将 _myController 对象设置为被测控制器。

    public ControllerTestBase()
    {
        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"buildversion.json", optional: true)
            .AddEnvironmentVariables();
        _config = builder.Build();

        var services = new ServiceCollection()
            .AddEntityFrameworkInMemoryDatabase()
            .AddDbContext<MyDbContext>(options =>
            {
                options.UseInMemoryDatabase();
            })
            .AddScoped<IDataItemSaver, DataItemSQLStorageService>()
            .AddScoped<MyController>()
            .Configure<MyConfig>(_config.GetSection(nameof(MyConfig)));

        services
            .AddMvc(mvcOptions =>
                {
                    mvcOptions.Filters.AddService(typeof(GlobalExceptionFilter), 0);
                });

        _additionalDISetupActions?.Invoke(services);

        _serviceProvider = services.BuildServiceProvider();

        _myController = _serviceProvider.GetService<MyController>();
    }

再次测试很简单:

    [TestMethod]
    public void Prop3Required()
    {
        // Arrange
        var dataItem = new DataItem()
        {
            Prop1 = "Prop1",
            Prop2 = "Prop2"
        };

        // Act & Assert
        Assert.ThrowsException<ArgumentException>(() => _myController.Track(dataItem));
    }

我发现 ModelState.IsValidtrue 当 运行 单元测试时,即使我的 DataItem 缺少必需的属性(本例中的 Prop3 ).当使用相同的输入通过网络测试控制器时,验证工作正常(为 ModelState.IsValid 返回 false)。

如何从单元测试正确触发 ASPNET Core 逻辑以进行模型状态验证?

您应该查看使用 ASP.NET 核心 (https://docs.microsoft.com/en-us/aspnet/core/testing/integration-testing) 的集成测试,这是在测试上下文中托管应用程序并测试整个管道的一种非常简单的方法。
如文档中所述,您可以在测试方法中执行类似的操作:

_server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
_client = _server.CreateClient();
// Pass a not valid model 
var response = await _client.PostAsJsonAsync("Track", new DataItem());
Assert.IsFalse(response.IsSuccessStatusCode);

如果要进行纯单元测试,则需要手动模拟模型状态错误,因为模型状态验证仅在运行时触发。

_myController.ModelState.AddModelError("yourItemFieldHere", "Your validation type here");

有关详细信息,请参阅 https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing