2016-08-17 5 views
0

У меня есть контроллер API, который публикует команду с использованием NServiceBus. Я использую NUnit и NSubstitute для тестирования. Я хочу проверить, что некоторые свойства модели заполнены командойЕдиничный тест NService.Send от контроллера API

Вот мой контроллер с маршрутом.

[RoutePrefix("api/fileService")] 
public class FileServiceController : ApiController 
{ 
    [HttpPost] 
    [Route("releasefile")] 
    public async Task<IHttpActionResult> ReleaseFile(FileReleaseAPIModels.ReleaseFileModel model) 
    { 
     var currentUser = RequestContext.Principal?.Identity as ClaimsIdentity; 


     if (model.FileType.Equals("ProductFile")) 
     { 
      _logger.Info($"Releasing Product files for date: {model.FileDate.ToShortDateString()} "); 
      _bus.Send<IReleaseProductFiles>("FileManager.Service", t => 
      { 
       t.FileId = Guid.NewGuid(); 
       t.RequestedDataDate = model.FileDate; 
       t.RequestingUser = currentUser?.Name; 
       t.RequestDateTime = DateTime.Now; 
      }); 
     } 
     return Ok(); 
    } 

} 

В моем тесте я подставляю (mock) Ibus и пытаюсь подтвердить полученный звонок. Вот тестовый метод:

[Test] 
    public async Task TestReleaseProductsFile() 
    { 
     var bus = Substitute.For<IBus>(); 
     var dbContent = _container.Resolve<IFileManagerDbContext>(); 
     var apiContext = new FileServiceController(bus, dbContent); 

     //Create a snapshot 
     var releaseDate = DateTime.Now.Date; 
     var result = await apiContext.ReleaseFile(new ReleaseFileModel 
     { 
      FileDate = releaseDate, 
      FileType = "ProductFile" 
     }); 

     Assert.That(result, Is.Not.Null, "Result is null"); 

     Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok"); 

     bus.Received(1) 
      .Send<IReleaseProductFiles>(Arg.Is<string>("FileManager.Service"), Arg.Is<Action<IReleaseProductFiles>>(
       action => 
       { 
        action.FileId = Guid.NewGuid(); 
        action.RequestedDataDate = releaseDate; 
        action.RequestingUser = String.Empty; 
        action.RequestDateTime = DateTime.Now; 
       })); 
    } 

Это приводит к ошибке - даже если сообщение действительно отправлено. Вот сообщение об ошибке:

NSubstitute.Exceptions.ReceivedCallsException : Expected to receive exactly 1 call matching: 
    Send<IReleaseProductFiles>("Capelogic.Service", Action<IReleaseProductFiles>) 
Actually received no matching calls. 
Received 1 non-matching call (non-matching arguments indicated with '*' characters): 
    Send<IReleaseProductFiles>("Capelogic.Service", *Action<IReleaseProductFiles>*) 

Очевидно, что я не вижу здесь ничего очевидного.

ответ

2

Проблема здесь с аргументом Action<IReleaseProductFiles> для Send - мы не можем автоматически сказать, являются ли два разных действия одинаковыми. Вместо этого NSubstitute полагается на эквивалентные ссылки. Поскольку и тестовый, и производственный код создают собственный экземпляр Action, это всегда будет отличаться, и NSubstitute скажет, что вызовы не совпадают.

Есть few different options for testing this. Эти примеры относятся к Expression<Func<>>, но те же идеи относятся к Action<> с.

В этом случае я был бы соблазн проверить это косвенно:

[Test] 
public async Task TestReleaseProductsFile() 
{ 
    var bus = Substitute.For<IBus>(); 
    var returnedProductFiles = Substitute.For<IReleaseProductFiles>(); 

    // Whenever bus.Send is called with "FileManager.Service" arg, invoke 
    // the given callback with the `returnedProductFiles` object. 
    // We can then make sure the action updates that object as expected. 
    bus.Send<IReleaseProductFiles>(
      "FileManager.Service", 
      Arg.Invoke<IReleaseProductFiles>(returnedProductFiles)); 

    // ... remainder of test ... 

    Assert.That(result, Is.TypeOf<OkResult>(), "Status code is not ok"); 
    Assert.That(returnedProductFiles.FileId, Is.Not.EqualTo(Guid.Empty)); 
    Assert.That(returnedProductFiles.RequestedDataDate, Is.EqualTo(releaseDate)); 
    Assert.That(returnedProductFiles.RequestingUser, Is.EqualTo(String.Empty)); 
} 

Я рекомендовал бы иметь взгляд через ранее упомянутый ответ, хотя, чтобы увидеть, если есть лучше подходит для вашей ситуации.

+0

Perfect. Я просто должен был сделать одну модификацию. Вместо: Arg.Invoke > (возвращеноProductFiles)); Изменено TO: Arg.Invoke (возвращеноProductFiles)); – Bitmask

+0

@Bitmask: спасибо, исправили это в ответе. –

Смежные вопросы