Test unitaire du contrôleur API Web ASP.NET avec un faux HTTPContext

J’utilise l’approche suivante pour télécharger des fichiers via les contrôleurs API Web ASP.NET.

[System.Web.Http.HttpPost] public HttpResponseMessage UploadFile() { HttpResponseMessage response; try { int id = 0; int? qId = null; if (int.TryParse(HttpContext.Current.Request.Form["id"], out id)) { qId = id; } var file = HttpContext.Current.Request.Files[0]; int filePursuitId = bl.UploadFile(qId, file); } catch (Exception ex) { } return response; } 

Dans mes tests unitaires, j’ai créé manuellement une classe HTTPContext avant d’appeler l’action UploadFile :

 var request = new HttpRequest("", "http://localhost", ""); var context = new HttpContext(request, new HttpResponse(new SsortingngWriter())); HttpContext.Current = context; response = controller.UploadFile(); 

Malheureusement, je n’ai pas pu append de valeurs personnalisées à la collection de Form , car elle est en lecture seule. Aussi, je ne pouvais pas changer la collection de Files .

Existe-t-il un moyen d’append des valeurs personnalisées aux propriétés Form et Files de la Request d’ajout des données nécessaires (identifiant et contenu du fichier) lors du test unitaire?

Utilisez plutôt un framework moqueur comme Moq . Créez une maquette HttpRequestBase et une maquette HttpContextBase avec toutes les données dont vous avez besoin et définissez-les sur le contrôleur.

 using Moq; using NUnit.Framework; using SharpTestsEx; namespace StackOverflowExample.Moq { public class MyController : Controller { public ssortingng UploadFile() { return Request.Form["id"]; } } [TestFixture] public class WebApiTests { [Test] public void Should_return_form_data() { //arrange var formData = new NameValueCollection {{"id", "test"}}; var request = new Mock(); request.SetupGet(r => r.Form).Returns(formData); var context = new Mock(); context.SetupGet(c => c.Request).Returns(request.Object); var myController = new MyController(); myController.ControllerContext = new ControllerContext(context.Object, new RouteData(), myController); //act var result = myController.UploadFile(); //assert result.Should().Be.EqualTo(formData["id"]); } } } 

Puisque vous n’avez aucun contrôle sur ces classes, pourquoi ne pas envelopper / résumer la fonctionnalité derrière un contrôle

 IRequestService request; [HttpPost] public HttpResponseMessage UploadFile() { HttpResponseMessage response; try { int id = 0; int? qId = null; if (int.TryParse(request.GetFormValue("id"), out id)) { qId = id; } var file = request.GetFile(0); int filePursuitId = bl.UploadFile(qId, file); } catch (Exception ex) { //... } return response; } 

request correspond à l’un de vos types définis sur mesure IRequestService

 public interface IRequestService { ssortingng GetFormValue(ssortingng key); HttpPostedFileBase GetFile(int index); //...other functionality you may need to abstract } 

et peut être mis en œuvre comme cela pour être injecté dans votre contrôleur

 public class RequestService : IRequestService { public ssortingng GetFormValue(ssortingng key) { return HttpContext.Current.Request.Form[key]; } public HttpPostedFileBase GetFile(int index) { return new HttpPostedFileWrapper(HttpContext.Current.Request.Files[index]); } } 

dans votre test unitaire

 var requestMock = new Mock(); //you then setup the mock to return your fake data //... //and then inject it into your controller var controller = new MyController(requestMock.Object); //Act response = controller.UploadFile();