【问题标题】:In C#, what is wrong with my negative test of TryAsync?在 C# 中,我对 TryAsync 的否定测试有什么问题?
【发布时间】:2021-11-20 10:52:03
【问题描述】:

我有以下方法:

public TryAsync<bool> TryRelay(
    MontageUploadConfig montageData,
    File sourceFile,
    CancellationToken cancellationToken
) => new(async () =>
{
    byte[] fileContent = await _httpClient.GetByteArrayAsync(sourceFile.Url, cancellationToken);
    return await _attachmentController.TryUploadAttachment(montageData.EventId, fileContent, sourceFile.Name);
});

我创建了几个测试来证明它按预期工作。 我对阴性案例的测试失败了。

这是测试:

[Fact]
public static async Task TestRelayShouldCatchErrorsGettingFile()
{
    // Arrange
    Mock<IAttachmentControllerV6> mockAttachmentController = new();
    Mock<HttpMessageHandler> mockHttpMessageHandler = new();
    MontageUploadTaskProcessor mockProcessorUnderTest = CreateProcessor(mockAttachmentController, mockHttpMessageHandler);

    MontageUploadConfig montageData = new()
    {
        EventId = "Test001"
    };
    File sourceFile = new()
    {
        Name = "Test.pdf",
        Url = "https://www.example.com/test.pdf"
    };
    CancellationToken cancellationToken = default;

    const string message = "Expected Exception";
    mockHttpMessageHandler.SetupAnyRequest()
        .Throws(new SalesforceCacheException(message));

    // Act
    Result<bool> result = await mockProcessorUnderTest.TryRelay(montageData, sourceFile, cancellationToken)();

    // Assert
    Assert.True(result.IsFaulted);
    result.IfFail(exception =>
    {
        Assert.True(exception is Exception);
        Assert.Equal(message, exception.Message);
    });
}

这是错误:

WorkflowTests.TaskProcessor.OldOrg.MontageUploadTaskProcessorUnitTests.TestRelayShouldCatchErrorsGettingFile 资料来源:MontageUploadTaskProcessorUnitTests.cs 第 59 行持续时间: 144 毫秒

消息:SFCacheController.SalesforceCacheException:预期 例外

堆栈跟踪:ThrowException.Execute(Invocation invocation) 第 22 行 MethodCall.ExecuteCore(调用调用)第 97 行 Setup.Execute(调用调用)第 85 行 FindAndExecuteMatchingSetup.Handle(Invocation 调用,Mock mock) 第 107 行 IInterceptor.Intercept(Invocation 调用) 第 17 行 Interceptor.Intercept(IInvocation 底层) 第 107 行 AbstractInvocation.Proceed() HttpMessageHandlerProxy.SendAsync(HttpRequestMessage 请求, CancellationToken 取消令牌) HttpMessageInvoker.SendAsync(HttpRequestMessage 请求, CancellationToken 取消令牌) HttpClient.SendAsyncCore(HttpRequestMessage 请求, HttpCompletionOption 完成选项,布尔异步,布尔 emitTelemetryStartStop, CancellationToken cancelToken) HttpClient.GetByteArrayAsyncCore(HttpRequestMessage 请求, CancellationToken cancelToken) d.MoveNext() 行 140 --- 来自先前位置的堆栈跟踪结束 --- MontageUploadTaskProcessorUnitTests.TestRelayShouldCatchErrorsGettingFile() 第 81 行 --- 上一个位置的堆栈跟踪结束 ---

异常似乎是在调用TryRelay() 之后引发的,甚至在尝试任何断言之前。

我期望TryAsync 会捕获并装箱异常是不是错了? 我期望这在测试环境中工作是错误的吗? 我需要做什么才能通过此测试?

【问题讨论】:

  • 您最近获得并接受的这个答案 (stackoverflow.com/a/69358330/5311735) 不是讨论了完全相同的问题吗?
  • 它讨论了这个问题,但介于两者之间的某个地方试图实际创建一个单元测试来证明功能并防止回归,我意识到我遗漏了一些东西......我希望它在测试中一边。
  • 你仍然使用错误的方法(new(async () =&gt; ...)来创建 TryAsync,你没有使用库提供的函数LanguageExt.Prelude.TryAsync
  • 我以为我改变了...会再试一次,谢谢。 :-)
  • @Evk,这就是问题所在。谢谢!

标签: c# functional-programming moq xunit try-type


【解决方案1】:

您直接调用TryAsync,它只是一个函数,因此除非您使用TryAsync 上的扩展,否则它不会捕获任何内容,例如Match

您可以做的是为您的单元测试构建一个辅助扩展:

public static Task<bool> HasFailed<E, A>(this TryAsync<A> ma) where E : Exception =>
    ma.Match(Succ: _ => false,
             Fail: e => e is E);

然后你可以写:

TryAsync<X> ma = ...;

Assert.True(await ma.HasFailed<IOException, X>());

【讨论】:

  • louthster,感谢您的回复,但@Evk 已经诊断出问题:我需要使用LanguageExt.Prelude.TryAsync,所以它 解决问题。 (Match 已经在处理结果了,为时已晚。)
  • 我是 language-ext 的作者,所以我有点知道我在说什么;)这只是部分正确。该行末尾有一个(),它正在调用 TryAsync 委托,您不应该这样做,即使它在这种情况下有效,也不能保证在每种情况下都有效。推荐的方法是匹配或使用 IfSucc/IfFail。您还直接使用 Result&lt;A&gt;,这不是使用 Try 或 TryAsync 的推荐方式:github.com/louthy/language-ext/blob/main/LanguageExt.Core/…
  • Result&lt;A&gt; 可能会被弃用(或至少其 API 表面被弃用),因为它鼓励您在此处尝试的内容,并可能导致混乱的结果,也可能导致未捕获的异常。我一直在努力找出影响最小的方法,但它会消失。因此,为了代码的长期可维护性,请使用扩展方法。我不知道你的 lang-ext 旅程有多远,但如果你想更好地管理同步/异步副作用,那么我建议使用 Aff 和 Eff monads 而不是 TryAsync 和 Try。
  • 它们没有TryTryAsync 的任何问题,并且在处理副作用方面更强大:github.com/louthy/language-ext/wiki/…
  • Eff - 效果(或副作用)的缩写,Aff - 异步副作用的缩写。它们比Try 的简单try/catch 功能强大得多,因此名称反映了这一点。这些名称的灵感来自 PureScript 和 Haskell 世界的 EffAff。它们在其他语言中也有类似物,例如 Scala 中的 ZIO。
猜你喜欢
  • 2016-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多