【问题标题】:Cannot setup a Moq callback for MediatR无法为 MediatR 设置起订量回调
【发布时间】:2020-03-21 20:46:20
【问题描述】:

我正在编写一个测试来验证我的控制器是否使用预期的查询参数调用我的查询。这是我的查询类:

public class GetProducts : IRequest<IEnumerable<Product>>
{
    public int CategoryId { get; set; }
}

这实现了IRequest&lt;T&gt; MediatR 接口。

这是不起作用的测试用例:

[Theory]
[InlineData(1)]
public async Task GetProductsAsync_GivenValidRequestParameters_ReturnsListGetProductsResponseAsync(int categoryId)
{
    var expectedQuery = new GetProducts
    {
        CategoryId = categoryId
    };

    _mediatorMock
        .Setup(s => s.Send(It.IsAny<GetProducts>(), It.IsAny<CancellationToken>()))
        .Callback<GetProducts, CancellationToken>((query, ct) => query.Should().BeEquivalentTo(expectedQuery))
        .ReturnsAsync(Enumerable.Empty<Product>());

    var response = await _productsController.GetProductsAsync(categoryId);

    response.Result.Should().BeOfType<OkObjectResult>();
    _mediatorMock.Verify(s => s.Send(It.IsAny<GetProducts>(), It.IsAny<CancellationToken>()), Times.Once);
}

这是我正在测试的控制器:

[ApiController]
[Route("categories/{categoryId:int}/products")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
[TrackUsage]
public class ProductsController : ControllerBase
{
    private readonly IMediator _mediator;

    public ProductsController(IMediator mediator)
    {
        _mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<GetProductsResponse>>> GetProductsAsync([FromRoute]int categoryId)
    {
        var query = new GetProducts
        {
            CategoryId = categoryId
        };

        var products = await _mediator.Send(query);

        return Ok(products.ToResponse());
    }
}

它抱怨是因为它找不到以&lt;GetProducts, CancellationToken&gt; 作为参数的回调,即使它看起来是正确的。

我知道我可以使用 It.Is&lt;...&gt;(callback =&gt; true) 来检查每个属性,但可能会有包含多个属性的查询,我更愿意使用 FluentAssertion 对其进行测试。

【问题讨论】:

    标签: c# moq fluent-assertions mediatr


    【解决方案1】:

    通用Send 定义

    public interface IMediator
    {
        /// <summary>
        /// Asynchronously send a request to a single handler
        /// </summary>
        /// <typeparam name="TResponse">Response type</typeparam>
        /// <param name="request">Request object</param>
        /// <param name="cancellationToken">Optional cancellation token</param>
        /// <returns>A task that represents the send operation. The task result contains the handler response</returns>
        Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default);
    
        //...
    

    Source

    Callback 需要匹配提供的定义

    //...
    
    _mediatorMock
        .Setup(s => s.Send<IEnumerable<Product>>(It.IsAny<IRequest<IEnumerable<Product>>>(), It.IsAny<CancellationToken>()))
        .Callback<IRequest<IEnumerable<Product>>, CancellationToken>((query, ct) => 
            ((GetProducts)query).Should().BeEquivalentTo(expectedQuery)
        )
        .ReturnsAsync(Enumerable.Empty<Product>());
    
    //...
    

    【讨论】:

    • public class GetProducts : IRequest&lt;IEnumerable&lt;Product&gt;&gt; 但我的班级确实实现了这一点。 C#(或者更确切地说是 Moq)无法检测到这一点?
    • 确实有效。我现在很好奇为什么如果我提供GetProducts 而不是IRequest&lt;IEnumerable&lt;Product&gt; 它不起作用。但这是一个不同的问题。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 2012-08-26
    • 2016-11-25
    • 2015-10-29
    相关资源
    最近更新 更多