2017-04-06 5 views
5

Wir haben vor kurzem mit der Verwendung von MediatR begonnen, um Controller-Aktionen zu entwirren, indem wir ein großes Portal für Kunden mit einem neuen Faktor berücksichtigen und in C# umwandeln. Als Teil davon vergrößern wir auch unsere Unit-Test-Abdeckung, aber ich habe ein Problem beim Versuch, Mediatr selbst zu verspotten.Mocking MediatR 3 mit Moq

Der Befehl führt eine Menge Dinge aus, um einen Prozess zu initiieren, und ein Teil davon sendet eine Benachrichtigung. Die Benachrichtigung selbst wird von einem eigenen Handler behandelt und würde daher einem eigenen Komponententest unterzogen werden, so dass ich MediatR vortäuschen möchte, so dass der Anruf this.mediator.Send(message) nicht wirklich etwas bewirkt. Der Handler gibt ein Objekt zurück, aber wir kümmern uns in diesem Zusammenhang nicht darum, also behandeln wir es im Grunde wie eine void Rückgabe. Ich möchte nur überprüfen, dass Send einmal als Teil des Tests aufgerufen wurde. Allerdings wirft die Send Methode eine NullReferenceException und ich weiß nicht warum.

Ab Version 3 verwendet MediatR jetzt einen zweiten optionalen Parameter unter Send, einem CancellationToken, und Ausdrucksbäume erfordern, dass Sie sie explizit festlegen, sodass Sie einen Wert angeben müssen. Ich habe das vorher noch nicht erlebt und denke, dass dies ein Teil des Problems sein könnte, aber das könnte meinerseits eine Verschmelzung sein.

Hier ist eine Kürzungsabbildung.

SUT

public class TransferHandler : IAsyncRequestHandler<TransferCommand, TransferResult> 
{ 
    private readonly IMediator mediator; 

    public TransferHandler(IMediator mediator) 
    { 
     this.mediator = mediator; 
    } 

    public async Task<TransferResult> Handle(TransferCommand message) 
    { 
     // Other stuff. 
     var notification = new TransferNotificationCommand() 
     { 
      ClientId = message.clientId, 
      OfficeId = message.OfficeId, 
      AuthorityFileId = letter?.Id 
     }; 

     await this.mediator.Send(notification); // <=== This is where we get a NullReferenceException, even though nothing is actually null (that I can see). 

     return new TransferResult() 
     { 
      Transfer = transfer, 
      FileId = letter?.Id 
     } 
    } 
} 

-Test

public class TransferHandlerTests 
{ 
    [Theory] 
    [AutoData] 
    public async void HandlerCreatesTransfer(Mock<IMediator> mockMediator) 
    { 
     // Note that default(CancellationToken) is the default value of the optional argument. 
     mediator.Setup(m => m.Send(It.IsAny<TransferNotificationCommand>(), default(CancellationToken))).Verifiable("Notification was not sent."); 

     var handler = new TransferHandler(mediator.Object); 

     var actual = await handler.Handle(message); 

     mediator.Verify(x => x.Send(It.IsAny<CreateIsaTransferNotificationCommand>(), default(CancellationToken)), Times.Once()); 
    } 
} 

Was bin ich? Ich habe das Gefühl, irgendwo einen grundlegenden Fehler gemacht zu haben, aber ich bin mir nicht sicher, wo.

Antwort

8

Sie müssen mit dem Warten der asynchronen Operation der Send-Methoden fertig werden, da sie Aufgaben zurückgeben.

/// <summary> 
/// Asynchronously send a request to a single handler 
/// </summary> 
/// <typeparam name="TResponse">Response type</typeparam> 
/// <param name="request">Request object</param> 
/// <param name="cancellationToken">Optional cancellation token</param> 
/// <returns>A task that represents the send operation. The task result contains the handler response</returns> 
Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default(CancellationToken)); 

/// <summary> 
/// Asynchronously send a request to a single handler without expecting a response 
/// </summary> 
/// <param name="request">Request object</param> 
/// <param name="cancellationToken">Optional cancellation token</param> 
/// <returns>A task that represents the send operation.</returns> 
Task Send(IRequest request, CancellationToken cancellationToken = default(CancellationToken)); 

Das bedeutet, dass Sie die falsche Rückkehr eine Aufgabe haben brauchen die Asynchron-Prozess zu ermöglichen, den Fluss

mediator 
    .Setup(m => m.Send(It.IsAny<TransferNotificationCommand>(), It.IsAny<CancellationToken>())) 
    .ReturnsAsync(new Notification()) //<-- return Task to allow await to continue 
    .Verifiable("Notification was not sent."); 

//...other code removed for brevity 

mediator.Verify(x => x.Send(It.IsAny<CreateIsaTransferNotificationCommand>(), It.IsAny<CancellationToken>()), Times.Once()); 
+0

fortzusetzen Wie ich schon sagte - es etwas Grundsätzliches und dumm sein hatte !! Ich nahm an, dass, da mir die Rückkehr egal war, ich es weglassen konnte, obwohl ich dem Spötter überhaupt nicht gesagt hatte, was zu tun war, so dass keine Aufgabe zurückgegeben wurde. Macht jetzt vollkommen Sinn, danke! Ich habe Ihre Antwort jedoch bearbeitet, da die Rückkehr etwas aus war. –

+1

@StevePettifer, Ich war unsicher, was Ihre Antwort auf bereitgestellten Code in OP basierte. Ihr Update ist korrekt. – Nkosi

Verwandte Themen