2017-04-06 1 views
5

최근 MediatR을 사용하여 대규모 고객 대면 포털을 재조정하고 C#으로 변환 할 때 컨트롤러 조치를 덜 수 있습니다. 이 일환으로 단위 테스트 커버리지도 늘리고 있지만 MediatR 자체를 조롱하려고 할 때 문제가 발생했습니다.Moq를 사용하여 MediatR 3 조롱

명령은 프로세스를 시작하기 위해 많은 작업을 수행하며이 중 일부는 알림을 보냅니다. 알림 자체는 자체 처리기로 처리되므로 자체 단위 테스트의 대상이되므로 MediatR을 조롱하여 this.mediator.Send(message) 호출이 실제로 아무것도 수행하지 않도록하고 싶습니다. 처리기는 객체를 반환하지만이 문맥에서는 처리하지 않으므로 처리하려는 모든 의도와 목적에 대해 void 반환으로 처리합니다. 테스트의 일부로 한번만 Send을 호출했는지 확인하고 싶습니다. 그러나 Send 메서드는 NullReferenceException을 던지고 있으며 그 이유를 모르겠습니다.

버전 3부터 MediatR은 Send, CancellationToken에 두 번째 선택적 매개 변수를 사용하며, 식 트리를 사용하려면 명시 적으로 설정해야 값을 지정해야합니다. 전에도 이런 일이 발생하지 않았으며 내 마음 속에서 이것이 문제의 일부가 될 수 있다고 생각하지만, 이것은 내 마음에 걸리는 것일 수 있습니다.

여기에 잘린 그림이 있습니다.

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 
     } 
    } 
} 

테스트

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()); 
    } 
} 

나는 무엇을 놓치고? 나는 어딘가에서 근본적인 실수를 한 것처럼 느껴진다. 그러나 나는 어디 있는지 모른다.

답변

8

작업을 반환 할 때 Send 메서드의 비동기 작업을 기다리는 처리해야합니다. 당신이 말했듯이 비동기 프로세스가

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

흐름을 계속 할 수 있도록 모의 리턴에게 작업이 필요 의미

/// <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)); 

- 그것은 근본적이고 바보 같은해야했다! 나는 반환을 신경 쓰지 않았으므로 그것을 생략 할 수 있다고 생각 했었습니다. 사실 나는 모의 할 일을 전혀하지 않았기 때문에 무엇을해야할 지 아무 일도 없었습니다. 지금 당장 완벽 해. 고마워! 반환이 약간 밖으로 나가기 때문에 나는 너의 응답을 편집했다. –

+1

@StevePettifer, 귀하의 답변이 OP에서 제공된 코드를 기반으로 한 것이 확실하지 않았습니다. 업데이트가 정확합니다. – Nkosi

관련 문제