2016-03-23 99 views
2

我具有被永遠運行一個單元測試運行下去:單元測試與任務

[Test] 
public bool test() 
{ 
    manager.Send(10); 

    Thread.Sleep(1000); 

    manager.Messages.Should().HaveCount(10); 

    return true; 
} 

manager.Send()的方法是:

private void Send() 
{ 
    try 
    { 
     var entities = GetAllEntities(); 

     foreach (var group in entities.GroupBy(r => r.Priority)) 
     { 
      var tasks = group.Select(entity => Task.Factory.StartNew(() => manager.SendEntity(entity))).ToList(); 
      Task.WaitAll(tasks.ToArray()); 

      if (tasks.All(r => r.Result.Result == true)) 
      { 
       // some code here... 
      } 
     } 
    } 
    catch (Exception e) 
    { 
     logger.FatalException(e.Message, e); 
    } 
    finally 
    { 
     logger.Info("End..."); 
    } 
} 

和SendEntity()方法:

public Task<bool> SendEntity(DeferredEntity entity) 
{ 
    var taskCompletionSource = new TaskCompletionSource<bool>(); 

    try 
    { 
     logger.Info("Sending entity {0} with params: {1}", entity.Entity, GetEntityParams(entity)); 

     server.SendToServer(entity, (response, result) => 
     { 
      taskCompletionSource.SetResult(result); 
     }); 
    } 
    catch (Exception e) 
    { 
     logger.FatalException(e.Message, e); 
    } 

    return taskCompletionSource.Task; 
} 

in unit test manager.Send(10)is running running。我暴露了代碼,我發現問題出在

if (tasks.All(r => r.Result.Result == true)) 

調試器在此行停止並永久休眠。我做錯了什麼?我將單元測試方法的返回值添加到bool中(異步方法不會在void方法中拋出異常)。但它沒有幫助。你有什麼建議嗎?

回答

2

你會在那裏陷入僵局。 首先你不必與

Task.Factory.StartNew(() => manager.SendEntity(entity) 

看來SendToServer已經是異步啓動新的線程。

它還一個不好的做法,使用Task.Wait***/Task.Result,使用異步流程

private async Task Send() 
{ 
    try 
    { 
     var entities = GetAllEntities(); 

     foreach (var group in entities.GroupBy(r => r.Priority)) 
     { 
      var tasks = group 
       .Select(entity => manager.SendEntity(entity)) 
       .ToArray(); 

      var results = await Task.WhenAll(tasks); 
      if (results.All(result => result)) 
      { 
       // some code here... 
      } 
     } 
    } 
    catch (Exception e) 
    { 
     logger.FatalException(e.Message, e); 
    } 
    finally 
    { 
     logger.Info("End..."); 
    } 
} 

但是,如果你不希望重寫發送方法,你可以使用.ConfigureAwait(false)

return taskCompletionSource.Task.ConfigureAwait(false); 

但不管怎麼說,刪除StartNew - 你不需要這個。

+0

非常感謝!這樣可行!我刪除了StartNew並使用Task.WhenAll – Anton23

+2

我還注意到它是Bad(tm)和Evil(tm)使用Task.Factory.StartNew而不是Task.Run(這裏是由stephen cleary激發的:http: //blog.stephencleary.com/2013/08/startnew-is-dangerous.html) – kai