Как смоделировать метод с CancellationToken, переданным в качестве параметра? - PullRequest
1 голос
/ 02 апреля 2019

Я недавно изучаю и использую Polly для повышения устойчивости моего кода, особенно для политик тайм-аута и повторных попыток.Однако я не знаю, как тестировать код с помощью polly.Чтобы быть более конкретным, я не знаю, как смоделировать метод с токеном отмены в качестве его параметра.Ниже приведена структура моего кода

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();

}

Ответы [ 2 ]

0 голосов
/ 03 апреля 2019

@ Noremac прав (вы тестируете 2 элемента в одном модульном тесте).

Однако, чтобы ответить на вопрос «Как заставить Mock<T> вызвать исключение, когда CancellationToken отменено»: Use Returns<TParam1, ...>(Func<TResult, TParam1>) перегрузка.Я заменил AsyncTimeoutPolicy на CancellationTokenSource для ясности.

// 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 =>
        {
            // Spin until the token is cancelled
            while (true)
            {
                token.ThrowIfCancellationRequested();
                // Add some delay to make this not-CPU-bound
                await Task.Delay(100);
            }
        });

    var tcs = new CancellationTokenSource(1000);
    await new Caller().Get(source.Object, tcs.Token);
}
0 голосов
/ 03 апреля 2019

ваш код никогда не вызывает этот метод "c.TryCallThirdParty".

Вы пытались использовать Task.Delay(Timespan.FromSeconds(1)) вместо Thread.Sleep?Каждый раз лучше использовать Task.Delay вместо Thread.Sleep.

...