使用动态参数对 post 方法进行单元测试

Unit testing a post method with a dynamic argument

我的网络 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);
    }

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

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

请分享您的想法。

谢谢。

问题是被测方法假定 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);
}