Ожидаемый вызов теряет контекст в модульном тесте
У нас есть следующий код ASP.NET (я сократил его для ясности):
var httpContent = new StringContent(postData, Encoding.UTF8);
using (var client = this.GetClient(url, contentType))
{
using (var response = await client.PostAsync(url, httpContent).ConfigureAwait(true);
{
ret.Response = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
}
}
'client' - это объект HttpClient при запуске в PROD, но в нашем модульном тесте это:
MockRepository.GenerateMock<IHttpClient>();
Обратите внимание, что мы используем .ConfigureAwait (true). Причина этого заключается в том, что мы храним объекты в коллекции HttpContext.Current.Items (это, вероятно, не идеально, но это то, что есть). Если мы не сохранили контекст потока, то HttpContext.Current возвращается как ноль.
Все это работает, как и ожидалось, при запуске в PROD.
Однако при запуске модульного теста выполнение следующей строки теряет контекст и HttpContext.Current становится равным нулю:
await response.Content.ReadAsStringAsync().ConfigureAwait(true);
Примечание. Исходящий вызов PostAsync для заглушки поддерживает контекст.
Итак, как мы программируем заглушку?
using (var httpResponse = new HttpResponseMessage())
{
httpResponse.Content = new StringContent(msg, Encoding.UTF8);
httpResponse.StatusCode = HttpStatusCode.OK;
this.FakeHttpClient
.Stub(i => i.PostAsync("", "")).IgnoreArguments()
.Return(Task.FromResult(this.httpResponse)).Repeat.Once();
// Act
}
Когда тест запускается, данные возвращаются, поэтому поддельные объекты ведут себя отлично, за исключением того, что ReadAsStringAsync().ConfigureAwait(true) разрушает контекст.
StringContent не может быть смоделирован напрямую, так как не имеет конструктора без параметров. Я создал класс-обертку, чтобы посмотреть, смогу ли я это высмеять, но когда у меня был следующий код:
var fakeStringContent = MockRepository.GenerateStub<Wrap>();
fakeStringContent
.Stub(fsc => fsc.ReadAsStringAsync())
.Return(Task.FromResult("<response/>"))
.Repeat.Once();
Затем в строке.Stub(...) было выдано исключение:
System.InvalidOperationException: "Асинхронная операция не вернула объект System.Threading.Tasks.Task."