簡體   English   中英

如何使用作為參數傳遞的 CancellationToken 來模擬方法?

[英]How to mock a method with CancellationToken passed as parameter?

我最近正在學習和使用 Polly 來為我的代碼添加彈性,特別是對於超時和重試策略。 但是,我不知道如何使用 polly 對代碼進行單元測試。 更具體地說,我不知道如何模擬以 Cancellation Token 作為參數的方法。 下面是我的代碼結構

public class Caller
{
     private IHttpManager httpManager;
     private IAsyncPolicy<HttpResponseMessage> policyWrap;

     public Caller(IHttpManager httpManager, IAsyncPolicy<HttpResponseMessage> policyWrap)
     {
        this.httpManager= httpManager;
        this.policyWrap = policyWrap;
     }


     public async Task CallThirdParty()
     {      

        HttpResponseMessage httpResponse = await policyWrap.ExecuteAsync(async ct => await httpManager.TryCallThirdParty(ct), CancellationToken.None);

     }

}

public interface IHttpManager
{
    Task<HttpResponseMessage> TryCallThirdParty(CancellationToken cancellationToken);
}

下面是我打算運行但不知道如何運行的單元測試。

[Test]
public void TestBehaviourUnderTimeoutPolicy()
{
     // Set up the timeout policy such that the governed delegate will terminate after 1 sec if no response returned
     AsyncTimeoutPolicy<HttpResponseMessage> timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(1, TimeoutStrategy.Optimistic);


     // mock IHttpManager
     var mockHttpManager= new Mock<IHttpManager>();

     // THIS IS WHERE I'M HAVING TROUBLE WITH.
     // I want to simulate the behaviour of the method such that
     // it will throw an exception whenever the CancellationToken passed from the polly caller expires
     // But how can I do that with mock?
     mockHttpManager.Setup(m => m.TryCallThirdParty(It.IsAny<CancellationToken>()))).Returns(Task.Run(() => { Thread.Sleep(10000); return new HttpResponseMessage(); }));

     Caller c = new Caller(mockHttpManager.Object, timeoutPolicy);
     await c.CallThirdParty();

}

@Noremac 是對的(您在一個單元測試中測試了 2 個元素)。

但是,要回答“ CancellationToken時如何使Mock<T>拋出異常”的問題:使用Returns<TParam1, ...>(Func<TResult, TParam1>)重載。 為了清楚起見,我用CancellationTokenSource替換了AsyncTimeoutPolicy

// This test will perma-hang if the exception is not thrown
[TestMethod]
[ExpectedException(typeof(OperationCanceledException))]
public async Task TestMethod1()
{
    var source = new Mock<IHttpManager>();
    source.Setup(s => s.TryCallThirdParty(It.IsAny<CancellationToken>())).Returns<CancellationToken>(
        async token =>
        {
            // Wait until the token is cancelled
            await Task.Delay(Timeout.Infinite, token);
        });

    var tcs = new CancellationTokenSource(1000);
    await new Caller().Get(source.Object, tcs.Token);
}

您剪下的代碼永遠不會調用此方法“c.TryCallThirdParty”。

您是否嘗試使用Task.Delay(Timespan.FromSeconds(1))而不是Thread.Sleep 每次都使用 Task.Delay 而不是 Thread.Sleep 更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM