如何用NUnit正确测试ConsumersController的Get()方法?测试未通过
如何正确用NUnit测试ConsumersController的Get()方法
你的测试代码存在几个关键问题,导致测试无法通过,咱们一步步拆解问题并给出修正方案:
原控制器代码
public ConsumersController(IProvider<Consumer> provider) { this.provider = provider; } /// <summary> /// Get the list of consumers that you are allowed to see and serve /// </summary> /// <response code="200">Returns the consumers you are allowed to see and serve</response> [HttpGet] [ProducesResponseType(typeof(IEnumerable<Consumer>), 200)] [Produces(typeof(IEnumerable<Consumer>))] [SwaggerResponse((int)HttpStatusCode.OK, Type = typeof(IEnumerable<Consumer>))] public IEnumerable<Consumer> Get() { return this.provider.GetAll(); }
原测试代码的问题
[TestFixture] public class ConsumerTest { private readonly HttpClient consumerHttp; private readonly ConsumersController consumerControl; [Test] public async Task Get_ConsumersController() { var result = this.consumerControl.Get(); var response = await consumerHttp.GetAsync("http://localhost:9000/consumers"); response.EnsureSuccessStatusCode(); var consumerList = JsonConvert.DeserializeObject<IEnumerable<Consumer>>(await response.Content.ReadAsStringAsync()); var consumerTest = consumerList.First(); Assert.AreEqual(result.First().Name, consumerTest.Name); } }
核心问题分析
- 未初始化依赖项:
consumerControl和consumerHttp都是只读字段,但没有在构造函数或SetUp方法中初始化,运行时会直接抛出NullReferenceException。 - 混合测试策略:你同时混用了单元测试(直接调用控制器方法)和集成测试(发送HTTP请求)的逻辑,这两种测试的目标完全不同,不该放在同一个测试用例里。
修正方案:分两种测试场景处理
场景1:单元测试(验证控制器逻辑)
单元测试的核心是隔离依赖,通过模拟IProvider<Consumer>来验证控制器是否正确返回依赖提供的数据,不需要启动真实的API服务。
using Moq; using NUnit.Framework; // 引入你的项目命名空间 [TestFixture] public class ConsumerControllerUnitTest { private ConsumersController _controller; private Mock<IProvider<Consumer>> _mockProvider; // 每个测试前初始化依赖和控制器 [SetUp] public void Setup() { // 创建模拟的IProvider实例 _mockProvider = new Mock<IProvider<Consumer>>(); // 设置模拟数据:定义GetAll()方法的返回值 var testConsumers = new List<Consumer> { new Consumer { Name = "测试消费者1" }, new Consumer { Name = "测试消费者2" } }; _mockProvider.Setup(p => p.GetAll()).Returns(testConsumers); // 初始化控制器,注入模拟的依赖 _controller = new ConsumersController(_mockProvider.Object); } [Test] public void Get_ReturnsConsumersFromProvider() { // 调用控制器的Get方法 var result = _controller.Get(); // 验证结果是否符合预期 Assert.IsNotNull(result); Assert.AreEqual(2, result.Count()); Assert.AreEqual("测试消费者1", result.First().Name); // 验证依赖的GetAll()方法确实被调用了一次 _mockProvider.Verify(p => p.GetAll(), Times.Once); } }
场景2:集成测试(验证API端点)
如果要测试完整的API流程(包括路由、序列化、中间件等),应该使用ASP.NET Core官方的测试框架来创建测试用的HttpClient,无需手动指定本地地址。
using Microsoft.AspNetCore.Mvc.Testing; using Newtonsoft.Json; using NUnit.Framework; // 引入你的项目命名空间 [TestFixture] public class ConsumerIntegrationTest { private HttpClient _httpClient; [SetUp] public void Setup() { // 使用WebApplicationFactory创建测试用的HttpClient,自动启动测试服务器 var factory = new WebApplicationFactory<Program>(); // Program是你的项目入口类 _httpClient = factory.CreateClient(); } [Test] public async Task Get_ConsumersEndpoint_ReturnsValidData() { // 发送请求到API端点 var response = await _httpClient.GetAsync("/consumers"); // 确保响应状态码为200 response.EnsureSuccessStatusCode(); // 反序列化响应内容 var content = await response.Content.ReadAsStringAsync(); var consumerList = JsonConvert.DeserializeObject<IEnumerable<Consumer>>(content); // 验证返回数据的有效性 Assert.IsNotNull(consumerList); Assert.IsNotEmpty(consumerList); // 可根据实际业务逻辑添加更具体的断言 } }
选择适合你的测试场景,按照上面的代码调整后,测试就能正常运行了。
内容的提问来源于stack exchange,提问作者romimsk
相关产品推荐
相关产品推荐

