[英]Returning a Bad Request while setting up mock repository in an ASP.NET web api controller for a unit test
[英]Mock Request Object for Web API unit test
我想对我的Web API控制器进行单元测试。 我有一个问题,我的一个动作方法(POST)需要来自Request
对象的值,以获取控制器名称。 我正在使用NSubtitute,FluentAssertions来支持我的单元测试
这是我的控制器代码看起来像:
public class ReceiptsController : BaseController
{
public ReceiptsController(IRepository<ReceiptIndex> repository) : base(repository) { }
..... Other action code
[HttpPost]
public IHttpActionResult PostReceipt(string accountId, [FromBody] ReceiptContent data, string userId = "", string deviceId = "", string deviceName = "")
{
if (data.date <= 0)
{
return BadRequest("ErrCode: Save Receipt, no date provided");
}
var commonField = new CommonField()
{
AccountId = accountId,
DeviceId = deviceId,
DeviceName = deviceName,
UserId = userId
};
return PostItem(repository, commonField, data);
}
}
和我的控制器的基类:
public abstract class BaseController : ApiController
{
protected IRepository<IDatabaseTable> repository;
protected BaseController(IRepository<IDatabaseTable> repository)
{
this.repository = repository;
}
protected virtual IHttpActionResult PostItem(IRepository<IDatabaseTable> repo, CommonField field, IContent data)
{
// How can I mock Request object on this code part ???
string controllerName = Request.GetRouteData().Values["controller"].ToString();
var result = repository.CreateItem(field, data);
if (result.Error)
{
return InternalServerError();
}
string createdResource = string.Format("{0}api/accounts/{1}/{2}/{3}", GlobalConfiguration.Configuration.VirtualPathRoot, field.AccountId,controllerName, result.Data);
var createdData = repository.GetItem(field.AccountId, result.Data);
if (createdData.Error)
{
return InternalServerError();
}
return Created(createdResource, createdData.Data);
}
}
这是我成功创建场景的单元测试:
[Test]
public void PostClient_CreateClient_ReturnNewClient()
{
// Arrange
var contentData = TestData.Client.ClientContentData("TestBillingName_1");
var newClientId = 456;
var expectedData = TestData.Client.ClientData(newClientId);
clientsRepository.CreateItem(Arg.Any<CommonField>(), contentData)
.Returns(new Result<long>(newClientId)
{
Message = ""
});
clientsRepository.GetItem(accountId, newClientId)
.Returns(new Result<ContactIndex>(expectedData));
// Act
var result = _baseController.PostClient(accountId, contentData, userId);
// Asserts
result.Should().BeOfType<CreatedNegotiatedContentResult<ContactIndex>>()
.Which.Content.ShouldBeEquivalentTo(expectedData);
}
我不知道是否有任何方法可以从控制器中提取Request对象,或者有没有办法在单元测试中模拟它? 现在,此代码Request.GetRouteData()
在单元测试中返回null
。
您可以创建一个获取Request Data的接口(将Request对象传递给它)。 实现该接口并在Controller中用作依赖项。 然后,您可以在单元测试中轻松模拟此接口实现。
我终于找到了解决这个问题的方法。 所以基本上我必须创建一些配置相关的东西,以使我的单元测试工作。
我为此创建了一个helpers
类
public static class Helpers
{
public static void SetupControllerForTests(ApiController controller)
{
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;
}
}
然后在我的测试setup
上传递我的测试控制器
[SetUp]
public void SetUp()
{
clientsRepository = Substitute.For<IRepository<ContactIndex>>();
_baseController = new ClientsController(clientsRepository);
Helpers.SetupControllerForTests(_baseController);
}
我不知道这是否是最好的方法,但我更喜欢这种方式,而不是创建一个新的接口并将其注入我的控制器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.