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

C# AspNetCore上的单元测试控制器模型验证,c#,unit-testing,asp.net-core,asp.net-core-webapi,C#,Unit Testing,Asp.net Core,Asp.net Core Webapi,在一个ASPNET核心项目中,我试图创建一些单元测试来验证我的数据验证逻辑是否正常工作 我的控制器非常简单: [HttpPost] [Route("Track")] public void Track([FromBody] DataItem item) { if (!ModelState.IsValid) throw new ArgumentException("Bad request"); _dataItemSaver.SaveData(item); } [Test

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

我的控制器非常简单:

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

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

        // Act & Assert
        Assert.ThrowsException<ArgumentException>(() => _myController.Track(dataItem));
    }
我正在使用一个测试基类,它将
\u 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>();
    }
public ControllerTestBase()
{
var builder=new ConfigurationBuilder()
.AddJsonFile(“appsettings.json”,可选:false,reloadOnChange:true)
.AddJsonFile($“buildversion.json”,可选:true)
.AddenEnvironmentVariables();
_config=builder.Build();
var services=newservicecolection()
.AddEntityFrameworkInMemoryDatabase()
.AddDbContext(选项=>
{
options.UseInMemoryDatabase();
})
.addScope()文件
.addScope()文件
.Configure(_config.GetSection(nameof(MyConfig)));
服务
.AddMvc(MVCOPions=>
{
mvcopions.Filters.AddService(typeof(GlobalExceptionFilter),0);
});
_additionalDISetupActions?.Invoke(服务);
_serviceProvider=services.BuildServiceProvider();
_myController=\u serviceProvider.GetService();
}
测试同样非常简单:

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

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

        // Act & Assert
        Assert.ThrowsException<ArgumentException>(() => _myController.Track(dataItem));
    }
[TestMethod]
公共无效Prop3Required()
{
//安排
var dataItem=新的dataItem()
{
Prop1=“Prop1”,
Prop2=“Prop2”
};
//行动与主张
Assert.ThrowsException(()=>\u myController.Track(dataItem));
}
我发现,即使我的
DataItem
缺少必需的属性(
Prop3
),在运行单元测试时,
ModelState.IsValid
也是
true
)。使用相同的输入通过web测试控制器时,验证工作正常(对于
ModelState.IsValid
,返回
false


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

您应该看看与ASP.NET Core()的集成测试,这是在测试上下文中承载应用程序并测试整个管道的一种非常简单的方法。
如文档中所述,您可以在测试方法中执行以下操作:

_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);
\u server=newtestserver(new WebHostBuilder().usestaupt());
_client=_server.CreateClient();
//传递无效的模型
var response=wait_client.PostAsJsonAsync(“Track”,new DataItem());
Assert.IsFalse(response.issuccesstatuscode);

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

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

有关更多详细信息,请参见

ModelState
无效时,您不会真的抛出异常,是吗?我这样做了,并在全局异常筛选器中处理了异常,以使所有错误处理和格式保持在同一位置。可以将检查移动到筛选器并全局应用,但会保留抛出异常并在全局筛选器中处理它的方法。真的吗?您的方法应该返回视图,以便用户可以更正验证错误。我没有提到这是一个API方法。有一个指定的错误类型(
apierro
)将包含modelstate错误。
APIRROR
对象是根据遇到的错误类型在我的全局异常过滤器中组装的。谢谢,这正是我要找的!很高兴您提到TestServer及其集成测试功能,但问题是关于单元测试的问题。