2014-05-01 69 views
24

我正在设置一些单元测试,并使用Rhino Mocks来填充正在测试的对象。被模拟的东西之一是Task<HttpResponseMessage>,因为被测试的逻辑包含一个调用HttpClient以获得异步响应。如何模拟任务<>结果?

所以我已经开始建立这样的嘲笑:

var httpClient = MockRepository.GenerateMock<HttpClient>(); 
var taskFunc = MockRepository.GenerateMock<Func<HttpResponseMessage>>(); 
var responseTask = MockRepository.GenerateMock<Task<HttpResponseMessage>>(taskFunc); 
var response = MockRepository.GenerateMock<HttpResponseMessage>(); 

httpClient.Stub(c => c.PostAsJsonAsync<IEnumerable<LogMessage>>(Arg<string>.Is.Anything, Arg<IEnumerable<LogMessage>>.Is.Anything)).Return(responseTask); 
responseTask.Stub(t => t.Result).Return(response); 
response.Stub(r => r.IsSuccessStatusCode).Return(true); 

(以下简称“法案”的测试步骤将是实例化对象正在测试中,给它的httpClient,并运行的方法,它的“断言”通过的预期方法调用中对其提出的嘲笑将核实)

通过这个步进在调试器,还有在这条线无限期挂起:

responseTask.Stub(t => t.Result).Return(response); 

我对Rhino Mocks或C#异步方面没有太多的经验,所以我可能忽略了一些明显的东西。当然,目标是任何拨打.Result属性的电话都会返回response模拟。但它看起来像我的尝试本身可能是调用.Result,我希望等待无限期,因为它只是一个模拟,也许?

什么是正确的安排方式?实质上,我需要用模拟的HttpClient来提供我的对象,并声明使用特定参数调用了一个方法。

+1

大约一年前,我使用最小起订量做了大量嘲笑任务。除非我错了,否则你只需要将你传递给你的模拟responseTask的taskFunc替换掉即可。然后让那个模拟函数立即返回一个响应。 – Keith

+0

@凯蒂:有趣。那么只需创建一个真正的'Func '而不是一个模拟,它只返回?我只是试图这样:'Func taskFunc = delegate(){return response; };'并将'taskFunc'传递给'responseTask'模拟,但观察到相同的行为。 – David

+1

我不认为你需要一个真正的模拟任务。你需要模拟的是传递给任务的函数,所以它只会返回“x”。 – Keith

回答

37

最简单的事情就是与预期的结果返回一个完成的任务:

var responseTask = Task.FromResult(response); 

我想象的原因,这是挂了嘲笑任务从来没有开始,因此给定的FUNC不会运行。您可以在您的测试开始吧:

var responseTask = MockRepository.GenerateMock<Task<HttpResponseMessage>>(taskFunc); 
responseTask.Start(); 

但是没有理由嘲笑的任务,因为你可以很容易地创建直接完成/失败/取消的任务。

+0

看起来这是在做伎俩。有了这个,我还需要通过后两个'Stub()'调用来移除。 ('.Result'由你的回答处理,'.IsSuccessStatusCode'在尝试存根时抛出一个错误,但似乎在模拟中默认为'true')。谢谢! – David

+0

谢谢,这也帮助了我! – Aaron