2016-11-29 39 views
5

Mam w sterowniku WebApi metodę, dla której chcę napisać testy jednostkowe. Jest to, jak wygląda moja metoda kontroler:Urządzenie do ładowania plików z 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}); 
    } 

Jak można drwić obiektu żądania w testowanie jednostkowe? Próbowałem po, ale napotkał problemy z IFormFileCollection. Poniższa linia rzutów błędach:

interfejs System.ArgumentException Nie znaleziono

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

Szczegółowy ślad stosu:

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) 

Myślę, że nie zbudowałem testu właściwie, ale bystre oko może wskazać mi właściwy kierunek.

+0

'wpadł problemów z IFormFileCollection. "Jakie problemy? wyjaśnij – Nkosi

+0

@Nkosi Zobacz moją aktualizację, aby uzyskać więcej informacji. Mam nadzieję, że wyjaśniłem to lepiej. – user869375

+0

Nie powinieneś wyskakiwać HttpContext, Request, Forms i Files i ustawiać je tak moqHttpContext.Returns (moqRequest.Object) moqRequest.Returns (moqForms.Object) i moqForms.Returns (moq.Files)? –

Odpowiedz

3

Dla każdego, kto stoi podobny problem, oto co zrobiłem, aby uzyskać jego pracy -

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

Doskonały kod. Nie trzeba próbować, gdy implementacje są publiczne i bardzo proste! –