首页 > 解决方案 > 使用动态参数对 post 方法进行单元测试

问题描述

我的 web api 控制器中有一个带有动态参数的 post 方法

 public IEnumerable<Product> Post([FromBody]dynamic value)
    {
        int productId;
        try
        {
            productId = Convert.ToInt32(value.productId.Value);
        }
        catch
        {

            return null;
        }
        return _data.Products.Where(y => y.Id == productId).ToList();        
    }

我正在尝试使用 Moq 框架工作对此进行单元测试,这就是我所拥有的

 public void PostRequestWithSingleProductTest()

    {
        var reqBody = new {productId = 1};

        var reqObject = new Mock<HttpRequestMessage>();
        reqObject.Setup(rq => rq.ToString()).Returns(JsonConvert.SerializeObject(reqBody));

        var response = _productController.Post(reqObject.Object);


        Assert.IsNotNull(response);
    }

响应始终为空,当我调试测试时,我可以看到传递的值是 {{productId:1}} 但编译器由于某种原因无法读取它并且它正在抛出Microsoft.CSharp.Runtime .Binder 异常

我已使用 assembly: InternalsVisibleTo()将测试程序集标记为朋友。

请分享你的想法。

谢谢。

标签: c#unit-testingasp.net-web-apiasp.net-web-api2

解决方案


问题是被测方法假定productId是可为空的,因此.Value. 当测试通过实际整数而不是可空整数时发生异常。

public void PostRequestWithSingleProductTest() {
    //Arrange
    int? productId = 1;
    var value = new { productId };

    //assuming _productController already created and injected with dependency

    //Act
    var response = _productController.Post(value);

    //Assert
    Assert.IsNotNull(response);
}

理想情况下,您应该使用强类型模型

public class PostProductModel {
    [Required]
    public int productId { get; set; }
}

这将允许框架进行正确的模型绑定

public IHttpActionResult Post([FromBody]PostProductModel value) {
    if(ModelState.IsValid) {
        var result = _data.Products.Where(y => y.Id == value.productId).ToList();        
        return Ok(result);
    }
    return BadRequest(ModelState);
 }

并大大简化了对目标方法进行单元测试的能力。

public void PostRequestWithSingleProductTest() {
    //Arrange
    var value = new PostProductModel { productId = 1 };

    //assuming _productController already created and injected with dependency

    //Act
    var response = _productController.Post(value) as OkObjectResult;

    //Assert
    Assert.IsNotNull(response);
}

推荐阅读