Ok() 的部分模拟给了我 "Value cannot be null"。 (参数'result')
Partial mock of Ok() gives me "Value cannot be null". (Parameter 'result')
在 ASP.NET 核心 Web 应用程序 API 模板项目中,如果我创建部分模拟和 return 一个 OK(someObject),我总是会收到一条错误消息,提示“值不能是无效的。 (参数'result')'
有趣的是,当我 运行 应用程序 (F5) 时,它工作正常。
不起作用的是使用 Moq 的单元测试。然后我得到这个错误。
我正在使用:
.NET Core 3.0(我在使用 2.1 时也遇到这个错误)。
最新起订量4.13.1
最新的 xunit 2.4.0
控制器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace MyTest.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : BaseAccessController
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController()
{
}
[HttpGet]
public async Task<ActionResult<WeatherForecast>> Get()
{
try
{
int userId = 3;
if (HasAccess(userId) == false)
return Forbid();
var rng = new Random();
return Ok(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray()); // This is where the error happens!
}
catch (Exception ex)
{
throw;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace MyTest.Controllers
{
public class BaseAccessController : Controller
{
protected virtual bool HasAccess(int userId)
{
return true;
}
}
}
单元测试:
using System;
using Microsoft.AspNetCore.Mvc;
using Moq;
using Moq.Protected;
using MyTest;
using MyTest.Controllers;
using Xunit;
namespace XUnitTestProject1
{
public class UnitTest1
{
interface IBaseAccessControllerProtectedMembers
{
bool HasAccess(int userId);
}
[Fact]
public async void MyUnitTest()
{
// Arrange
var mockController = new Mock<WeatherForecastController>();
mockController.Protected()
.As<IBaseAccessControllerProtectedMembers>()
.Setup(x => x.HasAccess(3))
.Returns(true);
// Act
var result = await mockController.Object.Get();
// Assert
var actionResult = Assert.IsType<ActionResult<WeatherForecast>>(result);
var returnValue = Assert.IsType<WeatherForecast>(actionResult.Value);
}
}
}
这是一个XY problem。
首先,动作定义为return
public async Task<ActionResult<WeatherForecast>> Get()
然而没有等待并且它还尝试returnWeatherForecast
的集合
return Ok(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray());
其次,如果使用 ActionResult<T>
,则无需手动执行 Ok(..)
结果。只是 return 预期的对象。
引用Controller action return types in ASP.NET Core Web API
所以我首先建议重构该操作以遵循文档中建议的语法
[HttpGet]
public async Task<ActionResult<WeatherForecast[]>> Get() { //Note the array
try {
int userId = 3;
if (HasAccess(userId) == false)
return Forbid();
var rng = new Random();
WeatherForecast[] results = await Task.Run(() => Enumerable
.Range(1, 5).Select(index => new WeatherForecast {
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray()
);
return results;
} catch (Exception ex) {
throw;
}
}
测试还应遵循正确的异步语法并声明预期的 return 类型
[Fact]
public async Task MyUnitTest() {
// Arrange
var mockController = new Mock<WeatherForecastController>() {
CallBase = true; //so that it can call `HasAccess` without issue
};
// Act
ActionResult<WeatherForecast[]> actionResult = await mockController.Object.Get();
// Assert
Assert.IsNotNull(actionResult);
var returnValue = Assert.IsType<WeatherForecast>(actionResult.Value);
}
我只需要将 mockController 更改为:
var mockController = new Mock<PersonsController>(mockPersonsService.Object) { CallBase = true };
现在工作正常。谢谢!! :-)
在 ASP.NET 核心 Web 应用程序 API 模板项目中,如果我创建部分模拟和 return 一个 OK(someObject),我总是会收到一条错误消息,提示“值不能是无效的。 (参数'result')'
有趣的是,当我 运行 应用程序 (F5) 时,它工作正常。
不起作用的是使用 Moq 的单元测试。然后我得到这个错误。
我正在使用:
.NET Core 3.0(我在使用 2.1 时也遇到这个错误)。
最新起订量4.13.1
最新的 xunit 2.4.0
控制器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace MyTest.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : BaseAccessController
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController()
{
}
[HttpGet]
public async Task<ActionResult<WeatherForecast>> Get()
{
try
{
int userId = 3;
if (HasAccess(userId) == false)
return Forbid();
var rng = new Random();
return Ok(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray()); // This is where the error happens!
}
catch (Exception ex)
{
throw;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace MyTest.Controllers
{
public class BaseAccessController : Controller
{
protected virtual bool HasAccess(int userId)
{
return true;
}
}
}
单元测试:
using System;
using Microsoft.AspNetCore.Mvc;
using Moq;
using Moq.Protected;
using MyTest;
using MyTest.Controllers;
using Xunit;
namespace XUnitTestProject1
{
public class UnitTest1
{
interface IBaseAccessControllerProtectedMembers
{
bool HasAccess(int userId);
}
[Fact]
public async void MyUnitTest()
{
// Arrange
var mockController = new Mock<WeatherForecastController>();
mockController.Protected()
.As<IBaseAccessControllerProtectedMembers>()
.Setup(x => x.HasAccess(3))
.Returns(true);
// Act
var result = await mockController.Object.Get();
// Assert
var actionResult = Assert.IsType<ActionResult<WeatherForecast>>(result);
var returnValue = Assert.IsType<WeatherForecast>(actionResult.Value);
}
}
}
这是一个XY problem。
首先,动作定义为return
public async Task<ActionResult<WeatherForecast>> Get()
然而没有等待并且它还尝试returnWeatherForecast
return Ok(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray());
其次,如果使用 ActionResult<T>
,则无需手动执行 Ok(..)
结果。只是 return 预期的对象。
引用Controller action return types in ASP.NET Core Web API
所以我首先建议重构该操作以遵循文档中建议的语法
[HttpGet]
public async Task<ActionResult<WeatherForecast[]>> Get() { //Note the array
try {
int userId = 3;
if (HasAccess(userId) == false)
return Forbid();
var rng = new Random();
WeatherForecast[] results = await Task.Run(() => Enumerable
.Range(1, 5).Select(index => new WeatherForecast {
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray()
);
return results;
} catch (Exception ex) {
throw;
}
}
测试还应遵循正确的异步语法并声明预期的 return 类型
[Fact]
public async Task MyUnitTest() {
// Arrange
var mockController = new Mock<WeatherForecastController>() {
CallBase = true; //so that it can call `HasAccess` without issue
};
// Act
ActionResult<WeatherForecast[]> actionResult = await mockController.Object.Get();
// Assert
Assert.IsNotNull(actionResult);
var returnValue = Assert.IsType<WeatherForecast>(actionResult.Value);
}
我只需要将 mockController 更改为:
var mockController = new Mock<PersonsController>(mockPersonsService.Object) { CallBase = true };
现在工作正常。谢谢!! :-)