2017-05-10 29 views
0

假设我有一个简单的API类像这样,在外部调用时,但如果它没有完成的例外是5秒钟后抛出:C# - 测试断言组件超时X秒后

public class Api 
{ 
    private readonly IConnector connector; 

    public Api(IConnector connector) 
    { 
     this.connector = connector; 
    } 

    public string GetSomething() 
    { 
     var timer = new System.Timers.Timer(5000); 
     timer.Elapsed += TimeOut; 

     timer.Start(); 
     //some external call which takes time 
     connector.Retrieve(); 
     timer.Stop(); 

     return "Something"; 
    } 

    private void TimeOut(object sender, ElapsedEventArgs e) 
    { 
     throw new TimeoutException("Timed out!"); 
    } 
} 

使用NUnit或其他方法,我该如何去测试上述请求需要8秒时抛出异常,但当请求需要3秒时成功?

我已经试过以下:

[TestFixture] 
public class ApiTests 
{ 
    IConnector mockConnector; 
    Api api; 

    [SetUp] 
    public void Setup() 
    { 
     mockConnector = MockRepository.GenerateMock<IConnector>(); 
     api = new Api(mockConnector); 
    } 

    [Test] 
    public void Api_RetrieveTakes3Seconds_SomethingReturned() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(3000).ContinueWith(c => "Something").Result); 
     var response = api.GetSomething(); 

     Assert.AreEqual("Something", response); 
    } 

    [Test] 
    public void Api_RetrieveTakes8Seconds_TimeOutExceptionThrown() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(8000).ContinueWith(c => "Something").Result); 
     var response = api.GetSomething(); 

     //assert an exception is thrown on the above 
    } 

} 

但如预期,这并不工作,当我调试任务只是等待在X秒存根线(api.GetSomething()之前,甚至称为)

如何调整这些测试以获得所需的行为?

作为一个额外的好处,如果可以不必等待其余的运行,这将是非常好的。

+0

也许尝试“mockConnector.Stub(c => c.Retrieve())。Return(()=> Task.Delay(3000).ContinueWith(c =>”Something“)。Result);”让你的代码在正确的线上等待? – JBdev

回答

0

可以测试与“Assert.Throws”异常NUnit的assert.You可以测试出一个值后的时间x量恢复使用这样一个秒表:

[Test] 
    public void Api_RetrieveTakes3Seconds_SomethingReturned() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(3000).ContinueWith(c => "Something").Result); 
     topwatch sw = new Stopwatch(); 
     sw.Start(); 
     var response = api.GetSomething(); 
     sw.Stop(); 
     Assert.That(sw.ElapsedMilliseconds, Is.LessThanOrEqualTo(3000));  } 

    [Test] 
    public void Api_RetrieveTakes8Seconds_TimeOutExceptionThrown() 
    { 
     mockConnector.Stub(c => c.Retrieve()).Return(Task.Delay(8000).ContinueWith(c => "Something").Result); 

     Assert.Throws(Exception,()=> api.GetSomething()); 
    } 

您需要添加一点缓冲区,因为你的测试正在等待3秒钟,所以你应该检查测试返回的时间少于3.1秒或类似的东西。

+0

嗯,但这似乎遭受同样的问题,当在存根上调用Retrieve()时不会发生人为延迟 - 它仅在创建存根时发生。 Retrieve()调用仍然是即时的。 – FBryant87

0

对于幸福的路径,尝试

Assert.That(() => api.GetSomething(), Is.EqualTo(expected).After(3).Seconds)); 

您可能需要,因为它是受延迟调整时间。

失败,你需要注入模拟或假冒成API时间过长,然后...

Assert.That(() => api.GetSomething(), Throws.Typeof<MyException>()); 

这是所有论坛的代码,所以看的错误。 :-)

+0

谢谢,但是它使得Retrieve()的模拟存根(stub)占用太长的时间,这是问题所在。如何才能做到这一点? – FBryant87

+0

不是一个犀牛的家伙,但我认为其他答案告诉你如何做到这一点。 – Charlie