Test unitaire ASP.NET WebApi avec Request.CreateResponse

147

J'essaie d'écrire des tests unitaires pour mon ApiController et j'ai rencontré des problèmes. Il existe une méthode d'extension intéressante appelée Request.CreateResponse qui aide beaucoup à générer une réponse.

public HttpResponseMessage Post(Product product)
{
  var createdProduct = repo.Add(product);
  return this.Request.CreateResponse(HttpStatusCode.Created, createdProduct);
}

Existe-t-il un moyen de se moquer de CreateResponse sans utiliser de simulations partielles ou d'utiliser directement "new HttpResponseMessage (...)"?

comme un
la source
1
Pourquoi voulez-vous vous moquer du CreateResponse? Pourquoi ne pas affirmer sur les propriétés renvoyées HttpResponseMessage Contentet StatusCodeque les valeurs correctes sont définies?
nemesv
3
Si j'exécute cette méthode sous forme de tests unitaires, elle échouera, sauf que la configuration n'est pas définie.
asa
1
Ok, honte sur moi, je juste besoin de this.Request.CreateResponse d'écriture (HttpStatusCode.Accepted, createdProduct, GlobalConfiguration.Configuration)
asa

Réponses:

243

Une autre façon de résoudre ce problème est de faire ce qui suit:

controller.Request = new HttpRequestMessage();
controller.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, 
                                  new HttpConfiguration());

Si vous effectuez une mise à niveau vers webapi 5.0, vous devrez changer cela en:

controller.Request = new HttpRequestMessage();
controller.Request.SetConfiguration(new HttpConfiguration());

La raison pour laquelle vous devez le faire est que vous devez avoir Requestrenseigné le contrôleur, sinon les méthodes d'extension Requestne fonctionneront pas. Vous devez également avoir un HttpConfigurationensemble sur la demande, sinon le routage et d'autres parties du pipeline ne fonctionneront pas correctement.

jonnii
la source
Oui, cela pourrait également fonctionner, mais il semble que Request.CreateResponse fonctionne également.
asa
4
L'ajout de GlobalConfiguration.Configuration laissait toujours la demande nulle. La définition de la demande a fonctionné pour moi, mais ce n'était pas la fin de mes problèmes car mon action appelait également Url.Link et le nom de l'itinéraire n'était pas défini.
foolshat
Aide pour la configuration de l'itinéraire stackoverflow.com/questions/11779311/…
foolshat
La définition de ControllerContext après cet appel me donne également cette erreur, mais uniquement avec WebApi 5.0.0. Mais si je définis l'objet HttpConfiguration sur la demande en dernier , cela fonctionne bien.
mikebridge
Cela fonctionne parfaitement, mais je ne comprends pas pourquoi cela fonctionne. Pourriez-vous expliquer cela dans la réponse?
Jan_V
24

Vous pouvez configurer l'objet contrôleur pour la testabilité comme ceci:

var config = new HttpConfiguration();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/products");
var route = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "products" } });

controller.ControllerContext = new HttpControllerContext(config, routeData, request);
controller.Request = request;
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;

Copié de l'article de blog complet de Peter Provost sur l' API Web ASP.NET de test unitaire .

mono68
la source
1
Vous pouvez également être intéressé par les documents MS liés à ceci: docs.microsoft.com/en-us/aspnet/web-api/overview/ ... Vous devrez peut-être également ajouter des références à System.Web.Http et System.Net. Http
Aaron Hoffman
4

Pour l'API Web 2, vous pouvez simplement ajouter

controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();

Ainsi

[TestMethod]
public void GetReturnsProduct()
{
    // Arrange
    var controller = new ProductsController(repository);
    controller.Request = new HttpRequestMessage();
    controller.Configuration = new HttpConfiguration();

    // Act
    var response = controller.Get(10);

    // Assert
    Product product;
    Assert.IsTrue(response.TryGetContentValue<Product>(out product));
    Assert.AreEqual(10, product.Id);
}

Il est important de définir la demande et la configuration sur le contrôleur. Sinon, le test échouera avec une ArgumentNullException ou InvalidOperationException.

Voir ici pour plus d'informations.

Dan Friedman
la source
1

WebAPI 1 ici avec un problème similaire en utilisant VB.

J'ai réussi à des réponses hybrides ici pour que cela fonctionne aussi simple que ceci:

Dim request As HttpRequestMessage = New HttpRequestMessage()
Return request.CreateResponse(HttpStatusCode.BadRequest, myCustomClassObject, GlobalConfiguration.Configuration)

Juste poster au cas où cela aiderait quelqu'un.

Rudy Scoggins
la source
0

Dans votre classe de test, créez une instance de la classe de contrôleur. par exemplevar customerController= new CustomerController();

customerController.Request = new HttpRequestMessage();
customerController.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
Kiran Chaudhari
la source