2016-11-29 2 views
5

У меня есть метод в контроллере WebApi, для которого я хочу написать модульные тесты. Это как мой метод управления выглядит:Модуль тестирования файла с Moq .net Core

Controller.cs

public async Task<FileUploadDto> UploadGoalDocument(Guid id) 
    { 
     var file = this.Request?.Form?.Files.FirstOrDefault(); 
     FileUploadDto result = null; 

     if (file == null) 
     { 
      return this.CreateResponse(result); 
     } 

     //logic to store file in db 

     return this.CreateResponse(new FileUploadDto() { Id = document.Id, Name = document.Name, Uri = document.Uri}); 
    } 

Как я могу издеваться объектом запроса в модульном тестировании? Я пробовал следовать, но столкнулся с проблемами с IFormFileCollection. Следующая строка бросает ошибки:

интерфейс System.ArgumentException не найден

cc.Setup(x => x.HttpContext.Request.Form.Files).Returns(col.Object); 

ControllerTest.cs

public async Task Upload_document_should_upload_document_and_return_dto() 
    { 
     var fileDto = new FileUploadDto { Id = Guid.NewGuid(), Name = "dummy.txt" }; 

     var fileMock = new Mock<IFormFile>(); 
     //Setup mock file using a memory stream 
     using (var ms = new MemoryStream()) 
     { 
      using (var writer = new StreamWriter("dummy.txt")) 
      { 
       writer.WriteLine("Hello World from a Fake File"); 
       writer.Flush(); 
       ms.Position = 0; 
       fileMock.Setup(m => m.OpenReadStream()).Returns(ms); 

       var file = fileMock.Object; 
       this.goalService.Setup(m => m.UploadDocument(Guid.NewGuid(), file, "")) 
        .ReturnsAsync(new Services.DTO.FileUploadDto { Id = fileDto.Id, Name = fileDto.Name }); 

       var cc = new Mock<ControllerContext>(); 
       var col = new Mock<IFormFileCollection>(); 
       col.Setup(x=> x.GetFile("dummy.txt")).Returns(file); 
       cc.Setup(x => x.HttpContext.Request.Form.Files).Returns(col.Object); 
       this.controller.ControllerContext = cc.Object; 
       var result = await this.controller.UploadGoalDocument(Guid.NewGuid()); 

       //Asserts removed for simplicity 
      } 
     } 
    } 

Детальный трассировки стека:

System.RuntimeTypeHandle.VerifyInterfaceIsImplemented(RuntimeTypeHandle handle, RuntimeTypeHandle interfaceHandle) 
at System.RuntimeType.GetInterfaceMap(Type ifaceType) 
at Moq.Extensions.IsGetObjectDataVirtual(Type typeToMock) 
at Moq.Extensions.IsSerializableMockable(Type typeToMock) 
at Moq.SerializableTypesValueProvider.ProvideDefault(MethodInfo member) 
at Moq.Mock.GetInitialValue(IDefaultValueProvider valueProvider, Stack`1 mockedTypesStack, PropertyInfo property) 
at Moq.Mock.SetupAllProperties(Mock mock, Stack`1 mockedTypesStack) 
at Moq.Mock.<>c__DisplayClass72_0.<SetupAllProperties>b__0() 
at Moq.PexProtector.Invoke(Action action) 
at Moq.Mock.SetupAllProperties(Mock mock) 
at Moq.QueryableMockExtensions.FluentMock[T,TResult](Mock`1 mock, Expression`1 setup) 
at lambda_method(Closure) 
at Moq.Mock.GetInterceptor(Expression fluentExpression, Mock mock) 
at Moq.Mock.<>c__DisplayClass66_0`2.<SetupGet>b__0() 
at Moq.PexProtector.Invoke[T](Func`1 function) 
at Moq.Mock.SetupGet[T,TProperty](Mock`1 mock, Expression`1 expression, Condition condition) 
at Moq.Mock.<>c__DisplayClass65_0`2.<Setup>b__0() 
at Moq.PexProtector.Invoke[T](Func`1 function) 
at Moq.Mock.Setup[T,TResult](Mock`1 mock, Expression`1 expression, Condition condition) 
at Moq.Mock`1.Setup[TResult](Expression`1 expression) 

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

+0

'столкнулся с проблемами с IFormFileCollection. 'Какие проблемы? уточнить – Nkosi

+0

@Nkosi См. мое обновление для более подробной информации. Надеюсь, я объяснил это лучше. – user869375

+0

Разве вы не можите HttpContext, Request, Forms и Files и не устанавливаете их так moqHttpContext.Returns (moqRequest.Object) moqRequest.Returns (moqForms.Object) и moqForms.Returns (moq.Files)? –

ответ

3

Для тех, кто сталкивается подобной проблемой, вот что я сделал, чтобы заставить его работать -

ControllerTest.cs

[TestMethod] 
    public async Task Upload_document_should_upload_document_and_return_dto() 
    { 
     var goalId = Guid.NewGuid(); 
     var file = new Services.DTO.FileUploadDto { Id = goalId, Name = "dummy.txt", Uri = "path/to/file" }; 

     this.goalService.Setup(m => m.UploadDocument(It.IsAny<Guid>(), It.IsAny<IFormFile>(), It.IsAny<string>())).ReturnsAsync(file); 

     //**This is the interesting bit** 
     this.controller.ControllerContext = this.RequestWithFile(); 
     var result = await controller.UploadGoalDocument(goalId); 

     Assert.IsNotNull(result); 
     Assert.AreEqual(file.Id, result.Data.Id); 
     Assert.AreEqual(file.Name, result.Data.Name); 
     Assert.AreEqual(file.Uri, result.Data.Uri); 
    } 

    //Add the file in the underlying request object. 
    private ControllerContext RequestWithFile() 
    { 
     var httpContext = new DefaultHttpContext(); 
     httpContext.Request.Headers.Add("Content-Type", "multipart/form-data"); 
     var file = new FormFile(new MemoryStream(Encoding.UTF8.GetBytes("This is a dummy file")), 0, 0, "Data", "dummy.txt"); 
     httpContext.Request.Form = new FormCollection(new Dictionary<string, StringValues>(), new FormFileCollection { file }); 
     var actx = new ActionContext(httpContext, new RouteData(), new ControllerActionDescriptor()); 
     return new ControllerContext(actx); 
    } 
+0

Отличный код. Не нужно макет, когда реализация является общедоступной и очень простой! –

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