【问题标题】:Unit test for Exception secario using Mock使用 Mock 对异常 secario 进行单元测试
【发布时间】:2020-12-04 08:17:43
【问题描述】:

我有一个 API,其返回类型为 IActionResult。伪代码如下

public async Task<IActionResult> Getdata()
{
   var result = await _report.Getall(DateTime.UtcNow);
}

我正在尝试为此编写单元测试,如下所示。

[Test]
public async Task Error_code()
{
    _report.Setup(r => r.Getall(It.IsAny<DateTime>())).ThrowsAsync(new Exception("Error Message"));
    var result = await _reportCnt.Getdata(); //_reportCnt is object of the Controller
    Assert.AreEqual("Error Message",reuslt);
}

但我面临的问题是,一旦从 API 抛出错误,它就不会断言,单元测试失败并出现错误Exception of type 'System.Exception' was thrown

这三种方法我都试过了

var result = await _reportCnt.Getdata() as ObjectResult;
var result = await _reportCnt.Getdata() as ActionResult;
var result = await _reportCnt.Getdata() as ExceptionResult;

但不工作,抛出同样的问题。

我在这里缺少什么或任何建议?

【问题讨论】:

  • 尝试使用 [ExpectedException(typeof(Exception))] 属性注释您的测试方法。 [Test] 属性的正下方。
  • 我正在使用 NUnit,但 MsTest 中存在 ExpectedException。但是在 NUnit 中我们仍然有 Assert.throwsAsync()。但尝试相同它会引发不同的问题。您仍然可以提供代码参考或一些伪代码吗?

标签: c# unit-testing .net-core nunit asp.net-core-webapi


【解决方案1】:

在你设置好你的模拟来抛出一个异常之后,你可以期望通过像这样调用被测方法:

[Test]
public void Test1()
{
    _report.Setup(r => r.Getall(It.IsAny<DateTime>())).ThrowsAsync(new Exception("Error Message"));

    var exceptionThrown = Assert.ThrowsAsync<Exception>(async () => await _reportCnt.Getdata());

    Assert.AreEqual("Error Message", exceptionThrown.Message);
}

【讨论】:

  • ThrowsAsync 返回抛出的异常,可以检查。因此,也可以验证异常的消息(因为它是 OP 的意图)
  • 你完全正确,彼得,我错过了。我更新了我的答案,谢谢。
  • 还有一件小事。您的测试是同步的,所以 public void Test1() 就足够了。即使ThrowsAsync 接受异步委托,它也是executed synchronously
【解决方案2】:

这是一个测试默认 WeatherForecastController 返回 ActionResult 而不是 IActionResult 的示例。您可以在此处了解这些好处:

https://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-5.0#actionresultt-type

[Authorize]
[ApiController]
[Route("[controller]")]

public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public ActionResult<IEnumerable<WeatherForecast>> Get()
    {
        var rng = new Random();
        return 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();
    }
}

使用xUnit 进行测试,但您应该可以转换为NUnit

[Fact]
public void DummyTest()
{
    var logger = Mock.Of<ILogger<WeatherForecastController>>();
    var controller = new WeatherForecastController(logger);

    var result = controller.Get().Value.First();

    Assert.True(result.Date.Date == DateTime.Now.AddDays(1).Date, "Date is current date");

    Assert.Throws<ArgumentOutOfRangeException>(() => controller.Get().Value.ToList()[5]);
}

【讨论】:

  • 在我之前的项目中,我已经模拟了 ILogger,是的,它是完美的。但在我当前的上下文中,Ilogger 没有使用,我也没有尝试 {} catch {},因为我正在处理 ExceptionFilter。
  • 这如何回答 OP 的问题?
  • @PeterCsala 它显示了ASP.NET Web API 单元测试以及如何正确测试Controller。我同意一个更好的答案将包括一个async await 电话和NUnit 但不幸的是我在写答案时没有时间这样做,而且评论的代码太多了。
  • 据我了解,OP 的问题是关于如何验证引发异常的方法调用。您提供的示例不会出现异常。
  • @PeterCsala 非常正确,感谢您指出这一点。更新了验证引发异常的方法调用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-06
  • 1970-01-01
相关资源
最近更新 更多