2017-04-06 66 views
5

Kısa bir süre önce, büyük bir müşteri tarafındaki portalımızı yeniden hesaba kattığımızdan ve hepsini C# 'ye dönüştürdüğümüzden, kontrolör işlemlerini dağıtmamıza izin vermek için MediatR'yi kullanmaya başladık. Bunun bir parçası olarak ünite test kapsamımızı da arttırıyoruz, ancak MediatR'ın kendisiyle dalga geçmeye çalışırken bir problem yaşadım.MediatR 3'ü Moq ile eşleştirin

Komut, bir işlemi başlatmak için bir takım şeyler yapıyor ve bunun bir kısmı bildirim gönderiyor. Bildirimin kendisi kendi işleyicisi tarafından ele alınmaktadır ve bu nedenle kendi birim testine tabi olacaktır, bu yüzden MediatR ile alay etmek istiyorum, böylece this.mediator.Send(message) numaralı çağrı gerçekten hiçbir şey yapmıyor. İşleyici bir nesneyi döndürür ancak biz bu bağlamda umurumda değiliz, bu nedenle tüm amaçlara ve amaçlarımıza void dönüşü olarak davranıyoruz. Sadece testin bir parçası olarak Send'un bir kez çağrıldığını doğrulamak istiyorum. Ancak, Send yöntemi bir NullReferenceException atıyor ve nedenini bilmiyorum.

MediatR, sürüm 3 itibariyle Send, CancellationToken numaralı ikinci bir isteğe bağlı parametreyi alır ve ifade ağaçları bunu açıkça ayarlamanızı gerektirir, böylece bir değer belirtmeniz gerekir. Bunu daha önce hiç karşılaşmadım ve aklımda bunun bunun bir parçası olabileceğini hissediyorum ama bu benim tarafımdan bir parça olabilir.

İşte bir aşağı illüstrasyon burada.

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

Testi

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

ben eksik? Bir yerde temel bir hata yaptım gibi hissediyorum ama nerede emin değilim.

cevap

8

Görevler döndükten sonra Send yöntemlerinin asenkron işleminin beklemesini ele almanız gerekir. Eğer Dediğim gibi zaman uyumsuz işlem

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

akışı anlamına devam etmesi için sahte dönüşü görevi olması gerektiği anlamına gelmektedir

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

- bu temel ve aptal bir şey olması gerekiyordu !! Geri dönüşü umursamadığım için onu ihmal edebildiğimi varsayıyordum, aslında ne yapmam gerektiğini söyleyemedim, bu yüzden hiçbir görev iade edilmedi. Şimdi mükemmel bir anlam ifade ediyor, teşekkürler! Cevabınız biraz geri döndükçe cevabınızı düzenledim. –

+1

@StevePettifer, Yanıtınız OP'de sağlanan kodu temel aldığından emin değildim. Güncellemeniz doğru. – Nkosi