c# - 如何模拟 "Throws"和 "ThrowsAsync"中的异常类型

标签 c# unit-testing exception xunit fluent-assertions

我想为一组不同的异常类型编写一个单元测试。我的常用方法是对一组特定的测试输入使用 InlineAutoMoqData。这对于值来说效果很好,但我无法让它对于类型起作用。

您可以在下面找到我的想法/希望的解决方案:

[Theory]
[InlineAutoMockData(typeOf(HttpRequestException)] 
[InlineAutoMockData(typeOf(InvalidOperationException)] 
public async void MyTestFunction_Should_HandleExceptions(Type exceptionType, Mock<HttpClient> clientMock)
{
    // Arrange
    var cut = CreateCut();
    clientMock.Setup(c => c.SendAsync()).ThrowsAsync(new Exception()); // here I want to  create a generic Exception dependend on the exceptionType instead of "new Exception"

   // Act
   var result = cut.DoSomething();
   
   // Assert
   result.Should().BeTrue();
}

我可以添加一个 switch case 检查“exceptionType”并最小起订量客户端依赖它。这个解决方案有效,但感觉不“正确”。我认为必须有一个更优雅的解决方案。

最佳答案

xUnit 支持通用参数。 所以你应该能够做这样的事情。

[Theory]
[MemberData(nameof(Exceptions))]
#pragma warning disable xUnit1026 // Theory methods should use all of their parameters
public async Task MyTestFunction_Should_HandleExceptions<TException>(TException _, Mock<HttpClient> clientMock)
#pragma warning restore xUnit1026 // Theory methods should use all of their parameters
    where TException : Exception, new()
{
    // Arrange
    var cut = CreateCut();
    clientMock.Setup(c => c.SendAsync()).Throws<TException>();


    // Act
    var result = cut.DoSomething();

    // Assert
    result.Should().BeTrue();
}

public static TheoryData<Exception> Exceptions() => new()
{
    new HttpRequestException(),
    new InvalidOperationException()
};

由于我无法运行您的代码片段,因此这是我用来验证上述想法是否有效的代码。

[Theory]
[MemberData(nameof(Exceptions))]
#pragma warning disable xUnit1026 // Theory methods should use all of their parameters
public async Task MyTestFunction_Should_HandleExceptions<TException>(TException _)
#pragma warning restore xUnit1026 // Theory methods should use all of their parameters
    where TException : Exception, new()
{
    // Arrange
    var handlerMock = new Mock<HttpMessageHandler>();
    handlerMock
        .Protected()
        .Setup<Task<HttpResponseMessage>>(
            "SendAsync",
            ItExpr.IsAny<HttpRequestMessage>(),
            ItExpr.IsAny<CancellationToken>()
        )
        .Throws<TException>();

    var client = new HttpClient(handlerMock.Object)
    {
        BaseAddress = new Uri("http://test.com/")
    };
    var cut = new Cut(client);

    // Act
    var result = await cut.DoSomething();

    // Assert
    result.Should().BeTrue();
}

public static TheoryData<Exception> Exceptions() => new()
{
    new HttpRequestException(),
    new InvalidOperationException()
};

private class Cut
{
    private readonly HttpClient httpClient;

    public Cut(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public async Task<bool> DoSomething()
    {
        var result = await httpClient.SendAsync(new HttpRequestMessage());
        return result.IsSuccessStatusCode;
    }
}

关于c# - 如何模拟 "Throws"和 "ThrowsAsync"中的异常类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75947002/

相关文章:

c# - 每当更新另一个文本框时更新文本框

c# - 与 Windows 控件的 C++ 相比,clr 如何处理 C# 中的标准事件?

c# - 记录具有保存敏感数据(待散列)属性的对象

c# - 单元测试重组

unit-testing - 如何使用 jasmine 模拟 Angular 服务?

c# - ServiceBus 触发的 WebJob 应使用什么运行模式?

unit-testing - Spock 测试框架 : Difference between mock. getProperty ('name' ) vs getName()

java - 如何处理未经检查的异常?

PostgreSQL 自定义异常条件

android - 如何使用PackageManager.setComponentEnabledSetting