You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Razor Page中对Validator验证器执行验证测试

原理解答

this.factory的作用

你代码里的WebApplicationFactory<Startup>是ASP.NET Core官方提供的集成测试工具类,结合XUnit的IClassFixture特性,会在当前测试类的所有用例执行前,一次性启动一个和线上运行环境配置一致的内存级Web应用宿主,这个factory就是该测试宿主的实例,它完整保留了你项目中Startup/Program类里的所有服务注册、中间件配置、路由规则,无需你手动搭建测试依赖环境,也不需要真实部署Web服务就能执行测试逻辑。

factory.Services.GetService()的功能

factory.Services是测试宿主对应的依赖注入(DI)容器根实例,GetService<T>()是DI容器的标准服务获取方法:你传入要获取的服务类型作为泛型参数,方法会在容器的服务注册列表中查找该类型对应的实现类,如果找到了就返回实例,没找到则返回null。如果你确定服务必然已经注册,可以替换为GetRequiredService<T>(),该方法在找不到服务时会直接抛出异常,更便于定位注册问题。

注意:你当前的FoodItemValidator存在逻辑缺陷:errors是类级别的字段,每次调用IsValid方法不会清空历史错误,多次调用同一个验证器实例时错误会累加,建议修改为方法内部的局部变量,修复后的代码如下:

public class FoodItemValidator : IFoodItemValidator
{
    public string[] IsValid(FoodItem foodItem)
    {
        // 将errors移动到方法内部,每次调用重新初始化
        List<string> errors = new List<string>();
        if (string.IsNullOrWhiteSpace(foodItem.Name))
        {
            errors.Add("Name should contain a value and not a space.");
        }
        if (string.IsNullOrWhiteSpace(foodItem.Description))
        {
            errors.Add("Description should contain a value and not a space.");
        }
        if (foodItem.Price <= 0)
        {
            errors.Add("Price should be greater than 0.");
        }
        return errors.ToArray();
    }
}

另外需要确认你项目的Startup/Program类中已经注册了验证器服务:
services.AddScoped<IFoodItemValidator, FoodItemValidator>();

完整测试实现

以下是覆盖所有校验场景的测试代码,基于你现有的WebApplicationFactory框架编写:

using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Food.Project;

namespace Food.Project.Tests
{
    public class WebApplicationTests : IClassFixture<WebApplicationFactory<Startup>>
    {
        private readonly WebApplicationFactory<Startup> _factory;
        private readonly IFoodItemValidator _validator;

        public WebApplicationTests(WebApplicationFactory<Startup> factory)
        {
            _factory = factory;
            // 测试类初始化时直接获取验证器实例
            _validator = _factory.Services.GetRequiredService<IFoodItemValidator>();
        }

        [Fact]
        public void Validator_AllFieldsValid_ReturnsEmptyErrorArray()
        {
            // 构造完全合法的FoodItem
            var validItem = new FoodItem
            {
                Name = "汉堡",
                Description = "经典牛肉汉堡",
                Price = 29.9
            };

            var errors = _validator.IsValid(validItem);
            
            Assert.Empty(errors);
        }

        [Fact]
        public void Validator_NameIsEmpty_ReturnsNameError()
        {
            var invalidItem = new FoodItem
            {
                Name = "",
                Description = "经典牛肉汉堡",
                Price = 29.9
            };

            var errors = _validator.IsValid(invalidItem);
            
            Assert.Single(errors);
            Assert.Contains("Name should contain a value and not a space.", errors);
        }

        [Fact]
        public void Validator_DescriptionIsWhitespace_ReturnsDescriptionError()
        {
            var invalidItem = new FoodItem
            {
                Name = "汉堡",
                Description = "   ",
                Price = 29.9
            };

            var errors = _validator.IsValid(invalidItem);
            
            Assert.Single(errors);
            Assert.Contains("Description should contain a value and not a space.", errors);
        }

        [Fact]
        public void Validator_PriceIsZero_ReturnsPriceError()
        {
            var invalidItem = new FoodItem
            {
                Name = "汉堡",
                Description = "经典牛肉汉堡",
                Price = 0
            };

            var errors = _validator.IsValid(invalidItem);
            
            Assert.Single(errors);
            Assert.Contains("Price should be greater than 0.", errors);
        }

        [Fact]
        public void Validator_MultipleFieldsInvalid_ReturnsAllRelatedErrors()
        {
            var invalidItem = new FoodItem
            {
                Name = "",
                Description = "",
                Price = -10
            };

            var errors = _validator.IsValid(invalidItem);
            
            Assert.Equal(3, errors.Length);
            Assert.Contains("Name should contain a value and not a space.", errors);
            Assert.Contains("Description should contain a value and not a space.", errors);
            Assert.Contains("Price should be greater than 0.", errors);
        }
    }
}

内容的提问来源于stack exchange,提问作者Maria Hussey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 20:06:03