在WebApi中对WebApi控制器进行单元测试
本文关键字:WebApi 单元测试 控制器 中对 | 更新日期: 2023-09-27 18:26:51
我正试图对我的控制器进行单元测试,但一旦该控制器使用其嵌入的UrlHelper
对象,它就会抛出一个ArgumentNullException
。
我试图测试的动作是这样的:
public HttpResponseMessage PostCommandes(Commandes commandes)
{
if (this.ModelState.IsValid)
{
this.db.AddCommande(commandes);
HttpResponseMessage response = this.Request.CreateResponse(HttpStatusCode.Created, commandes);
// this returns null from the test project
string link = this.Url.Link(
"DefaultApi",
new
{
id = commandes.Commande_id
});
var uri = new Uri(link);
response.Headers.Location = uri;
return response;
}
else
{
return this.Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
我的测试方法如下:
[Fact]
public void Controller_insert_stores_new_item()
{
// arrange
bool isInserted = false;
Commandes item = new Commandes() { Commande_id = 123 };
this.fakeContainer.AddCommande = (c) =>
{
isInserted = true;
};
TestsBoostrappers.SetupControllerForTests(this.controller, ControllerName, HttpMethod.Post);
// act
HttpResponseMessage result = this.controller.PostCommandes(item);
// assert
result.IsSuccessStatusCode.Should().BeTrue("because the storage method should return a successful HTTP code");
isInserted.Should().BeTrue("because the controller should have called the underlying storage engine");
// cleanup
this.fakeContainer.AddCommande = null;
}
SetupControllerForTests
方法就是这个,如图所示:
public static void SetupControllerForTests(ApiController controller, string controllerName, HttpMethod method)
{
var request = new HttpRequestMessage(method, string.Format("http://localhost/api/v1/{0}", controllerName));
var config = new HttpConfiguration();
var route = WebApiConfig.Register(config).First();
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary
{
{
"controller",
controllerName
}
});
controller.ControllerContext = new HttpControllerContext(config, routeData, request);
controller.Request = request;
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
controller.Request.Properties[HttpPropertyKeys.HttpRouteDataKey] = routeData;
}
对于WebApi2来说,这是一个记录得很好的问题,例如,您可以在这里阅读更多关于它的信息("测试链接生成")。基本上,它可以归结为设置自定义ApiController.RequestContext
,或者模拟控制器的Url
属性。
问题是,在我的WebApi版本(Nuget包:Microsoft.AspNet.WebApi 4.0.20710.0/WebApi.Core.4.0.30506.0)中,ApiController.RequestContext
不存在,Moq不能模拟UrlHelper
类,因为它应该模拟的方法(Link
)是不可重写的,或者类似的东西(我没有详细讨论)。因为我正在使用WebApi 1。但是我的代码所基于的博客文章(以及许多其他文章)也使用V1。所以我不明白为什么它不起作用,最重要的是,我如何才能让它起作用。
谢谢!
不确定您链接到的文档自原始帖子以来是否已更新,但它们显示了一个模拟UrlHelper
和Link
方法的示例。
[TestMethod]
public void PostSetsLocationHeader_MockVersion()
{
// This version uses a mock UrlHelper.
// Arrange
ProductsController controller = new ProductsController(repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
string locationUrl = "http://location/";
// Create the mock and set up the Link method, which is used to create the Location header.
// The mock version returns a fixed string.
var mockUrlHelper = new Mock<UrlHelper>();
mockUrlHelper.Setup(x => x.Link(It.IsAny<string>(), It.IsAny<object>())).Returns(locationUrl);
controller.Url = mockUrlHelper.Object;
// Act
Product product = new Product() { Id = 42 };
var response = controller.Post(product);
// Assert
Assert.AreEqual(locationUrl, response.Headers.Location.AbsoluteUri);
}
因此,您需要模拟UrlHelper.Link方法。使用Typemock Isolator(给定链接的测试示例)可以很容易地完成:
[TestMethod, Isolated]
public void PostSetsLocationHeader_MockVersion()
{
// This version uses a mock UrlHelper.
// Arrange
ProductsController controller = new ProductsController(repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
string locationUrl = "http://location/";
// Create the mock and set up the Link method, which is used to create the Location header.
// The mock version returns a fixed string.
var mockUrlHelper = Isolate.Fake.Instance<UrlHelper>();
Isolate.WhenCalled(() => mockUrlHelper.Link("", null)).WillReturn(locationUrl);
controller.Url = mockUrlHelper;
// Act
Product product = new Product() { Id = 42 };
var response = controller.Post(product);
// Assert
Assert.AreEqual(locationUrl, response.Headers.Location.AbsoluteUri);
}