用于Web API单元测试的模拟请求对象

Mar*_*ino 3 c# asp.net unit-testing asp.net-web-api

我想对我的Web API控制器进行单元测试.我的一个操作方法(POST)有一个问题,它需要来自Requestobject的值,以获取控制器名称.我正在使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

和我的控制器的基类:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我成功创建场景的单元测试:

[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);
 }
Run Code Online (Sandbox Code Playgroud)

我不知道是否有任何方法可以从控制器中提取Request对象,或者有没有办法在单元测试中模拟它?现在这个代码Request.GetRouteData()返回null单元测试.

rea*_*ero 5

您可以创建一个获取Request Data的接口(将Request对象传递给它).实现该接口并在Controller中用作依赖项.然后,您可以在单元测试中轻松模拟此接口实现.