测试方法使用 XUnit 返回 Null 异常

问题描述 投票:0回答:1

我们正在使用 CQRS/Mediator 模式,我正在尝试为 API 编写一些单元测试,我从控制器开始。

这是我想为其编写单元测试的 CreateAync() 方法。

[HttpPost]
    [MustHavePermission(FSHAction.Create, FSHResource.Article)]
    [OpenApiOperation("Create new Article.", "Content State => Draft = 0 , Published = 1")]
    public async Task<ArticleDto> CreateAsync(CancellationToken cancellationToken, CreateArticleCommand request)
    {
        var article = await Mediator.Send(request, cancellationToken);

        article.CreatedByUser = await _userService.GetAsync(article.CreatedBy.ToString(), cancellationToken);

        article.LastModifiedByUser = await _userService.GetAsync(article.CreatedBy.ToString(),   cancellationToken);

        return article;
    }

这是 CreateCommand 类:

public class CreateArticleCommand : IRequest<ArticleDto>
{
    public CreateArticleCommand(string title, string content, Guid contentCategoryId, ContentItemState contentState, List<ContentTagDto> contentTags)
    {
        Title = title;
        Content = content;
        ContentCategoryId = contentCategoryId;
        ContentState = contentState;
        ContentTags = contentTags;
    }

    public string Title { get; set; } = default!;
    public string Content { get; set; } = default!;
    public Guid ContentCategoryId { get; set; }
    public ContentItemState ContentState { get; set; }
    public List<ContentTagDto> ContentTags { get; set; }

}

这是我的测试方法:

[Fact]
    public async Task CreateAsync_ReturnsValidArticleDto()
    {
        // Arrange
        var cancellationToken = CancellationToken.None;
        var controllerContext = new ControllerContext
        {
            HttpContext = _httpContext.Object
        };
        _articlesController.ControllerContext = controllerContext;
        var contentTag = new ContentTagDto(1, "test")
        {
            Id = 1,
            Title = "test"
        };

        var contentTagDtoList = new List<ContentTagDto>() { contentTag };
        var createArticleCommand = new CreateArticleCommand("Title", "content", Guid.NewGuid(), ContentItemState.Draft, contentTagDtoList);

        var mediatorMock = new Mock<IMediator>(); // Replace with your actual IMediator interface
        var userServiceMock = new Mock<IUserService>(); // Replace with your actual IUserService interface

        // Set up the Mediator mock to return a dummy ArticleDto
        mediatorMock
            .Setup(m => m.Send(createArticleCommand, cancellationToken))
            .ReturnsAsync(new ArticleDto { Id = Guid.NewGuid() });

        // Set up the UserService mock to return a dummy user
        var user = new UserDto { Id = Guid.NewGuid(), Email = "[email protected]", FirstName = "Test", LastName = "User" };
        _userService
            .Setup(x => x.GetAsync(_currentUserMock.Object.GetUserId().ToString(), CancellationToken.None))
            .ReturnsAsync(user);

        // Act
        var result = await _articlesController.CreateAsync(cancellationToken, createArticleCommand);

        // Assert
        Assert.NotNull(result);
    }

我得到 Null 异常,调试后我发现异常来自控制器中的 CreatAsync() 方法,看起来文章总是为空,我该如何解决这个“文章”空异常?

unit-testing .net-core asp.net-core-webapi xunit mediator
1个回答
0
投票

解决方案是嘲笑 Sender 而不是 Mediator。

首先必须在构造函数中注入ISender接口,然后在测试方法中使用它。

private readonly Mock<IUserService> _userService;
private readonly ArticlesController _articlesController;
private readonly Mock<ISender> _sender;
private readonly Mock<HttpContext> _httpContext;


public ArticlesControllerTests()
{
    _sender = new Mock<ISender>();
    _httpContext = new Mock<HttpContext>();
    
   _httpContext.Setup(ctx=>ctx.RequestServices.GetService(typeof(ISender)))
           .Returns(_sender.Object);
    _currentUserMock = new Mock<ICurrentUser>();

    _articlesController = new ArticlesController(_userService.Object);
    var controllerContext = new ControllerContext
    {
        HttpContext = _httpContext.Object
    };
    _articlesController.ControllerContext = controllerContext;
}

HttpContext
然后启动controllerContext也很重要。

对于测试方法,我使用 _sender 而不是 _mediator :

 //// Arrange
    var tesId = Guid.NewGuid();

    // -Create a test request
    var testRequest = new CreateArticleCommand("Test Title", "Test Content", Guid.NewGuid(), ContentItemState.Draft, new List<ContentTagDto>());

    // -Create a test article
    var testArticle = new ArticleDto
    {
        Id = Guid.NewGuid(),
        Title = testRequest.Title,
        Content = testRequest.Content,
        ContentCategoryId = testRequest.ContentCategoryId,
        ContentState = testRequest.ContentState,
        ContentTags = testRequest.ContentTags,
        CreatedBy = tesId,
        LastModifiedBy = tesId,
        CreatedByUser = new UserDto { Id = tesId, Email = "[email protected]", 
   FirstName = "Test", LastName = "User" }
    };

    _sender.Setup(m => m.Send(
        It.IsAny<CreateArticleCommand>(),
        It.IsAny<CancellationToken>())).ReturnsAsync(testArticle);

    //// Act
    var result = await _articlesController.CreateAsync(new 
    CancellationToken(), testRequest);

    //// Assert
    Assert.NotNull(result);

现在这个测试方法工作正常,我很高兴我可以自己解决这个问题:D

© www.soinside.com 2019 - 2024. All rights reserved.