2015-02-18 9 views
24

Da ich meine WCF-Methoden in Async konvertiert haben, sind meine Komponententests fehlgeschlagen, und ich kann nicht die richtige Syntax herausfinden, um sie zum Laufen zu bringen.Moq mit Task warten

Cllient Proxy-Klasse

public interface IClientProxy 
{ 
    Task DoSomething(CredentialDataList credentialData, string store); 
} 

Serviceklasse

public class CredentialSync : ICredentialSync 
{ 
    private ICredentialRepository _repository; 

    private IClientProxy _client; 

    public CredentialSync() 
    { 
     this._repository = new CredentialRepository(); 
     this._client = new ClientProxy(); 
    } 

    public CredentialSync(ICredentialRepository repository, IClientProxy client) 
    { 
     this._repository = repository; 
     this._client = client; 
    } 

    public async Task Synchronise(string payrollNumber) 
    { 
     try 
     { 
      if (string.IsNullOrEmpty(payrollNumber)) 
      { 
       .... some code 
       } 
      else 
      { 
       CredentialDataList credentialData = new CredentialDataList(); 
       List<CredentialData> credentialList = new List<CredentialData>(); 

       // fetch the record from the database 
       List<GetCredentialData_Result> data = this._repository.GetCredentialData(payrollNumber); 
       var pinData = this._repository.GetCredentialPinData(payrollNumber); 

       // get the stores for this employee 
       var storeList = data.Where(a => a.StoreNumber != null) 
        .GroupBy(a => a.StoreNumber) 
        .Select(x => new Store { StoreNumber = x.Key.ToString() }).ToArray(); 

       var credential = this.ExtractCredentialData(data, pinData, payrollNumber); 

       credentialList.Add(credential); 
       credentialData.CredentialList = credentialList; 

       foreach (var store in storeList) 
       {  
        //this line causes an Object reference not set to an instance of an object error 
        await _client.DoSomething(credentialData, store.StoreNumber); 

       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new FaultException<Exception>(ex); 
     } 
    } 

Testklasse

/// </summary> 
[TestClass] 
public class SynchTest 
{ 

    private Mock<ICredentialRepository> _mockRepository; 
    private Mock<IClientProxy> _mockService; 

    [TestInitialize] 
    public void Setup() 
    { 
     ... some setups for repository which work fine 
    } 

[TestMethod]  
    public async Task SynchroniseData_WithOneEmployee_CallsReplicateService() 
    { 
     this._mockService = new Mock<IClientProxy>(); 
     this._mockService.Setup(x=>x.DoSomething(It.IsAny<CredentialDataList>(), It.IsAny<string>())); 
     // arrange 
     string payrollNumber = "1"; 
     CredentialSync service = new CredentialSync(this._mockRepository.Object, this._mockService.Object); 

     // act 
     await service.Synchronise(payrollNumber); 

     // assert     
     this._mockService.VerifyAll(); 
    } 

Die erro r ist, wenn ClientProxy.DoSomething genannt:

Objektverweis nicht auf eine Instanz eines Objekts festgelegt

Die Parameter sowohl fein sind.

Wenn ich konvertieren meine ClientProxy.DoSomething Methode auf eine synchrone Methode (public void DoSomething(...)) der Code funktioniert gut, aber ich dies tun müssen asynchron

Antwort

54

DoSomething kehrt aufgerufen werden null stattdessen eine Task zurückzukehren, und so Sie Erhalten Sie eine Ausnahme, wenn Sie darauf warten. Sie müssen beim Erstellen des Mocks angeben, dass eine Task zurückgegeben werden soll.

In diesem Fall scheint es, dass Sie einfach eine bereits erledigte Aufgabe mit Task.FromResult zurückkehren können, so der Mock-Setup sollte wie folgt aussehen:

this._mockService.Setup(...).Returns(Task.FromResult(false)); 

Beginnend mit der nächsten Version von .Net (4.6) Sie können Task.CompletedTask

+5

Es ist in diesem Fall sollte beachtet werden, falsch ist nur ein Platzhalter, wird der Wert falsch von dem Schein ignoriert tatsächlich, es braucht nur eine Aufgabe, jede Aufgabe , fertigstellen. Es könnte genauso gut "foo" statt falsch sein ... – mcse3010

+0

@ mcse3010 in der Tat. – i3arnon

+1

Upvoted für die 4.6-Syntax, sehr kurz und bezeichnend für das, was es tatsächlich ist. – starmandeluxe

4

ich glaube, Sie die Task vom DoSomething Mock zurückkehren müssen verwenden

this._mockService.Setup(x=>x.DoSomething(It.IsAny<CredentialDataList>(), It.IsAny<string>())) 
           .Returns(Task.FromResult<int>(0)); 
+0

Oder mein Favorit ist '.Returns (Task.Delay (0));' –

10

können Sie die Menge an Unordnung in dem Code reduzieren, indem ReturnsAsync mit

this._mockService.Setup(...).ReturnsAsync(false);

Auf diese Weise kann den Task.FromResult Teil des

Code entfernen