繁体   English   中英

如何在 C# 的 CQRS 模式中对命令处理程序进行单元测试

[英]How to unit test Command Handler in CQRS pattern in C#

我正在 C# 中学习和练习 CQRS 和单元测试。 我需要知道如何在 CQRS 中对命令处理程序进行单元测试。

这是我的CreateAuthorCommand

public sealed class CreateAuthorCommand : ICommand<Author>
{
    public CreateAuthorCommand(string firstName, string lastName, DateTimeOffset dateOfBirth, string mainCategory, IEnumerable<CreateBookDto> books)
    {
        FirstName = firstName;
        LastName = lastName;
        DateOfBirth = dateOfBirth;
        MainCategory = mainCategory;
        Books = books;
    }

    public string FirstName { get; }
    public string LastName { get; }
    public DateTimeOffset DateOfBirth { get; private set; }
    public string MainCategory { get; }
    public IEnumerable<CreateBookDto> Books { get; }

    [AuditLog]
    [DatabaseRetry]
    internal sealed class AddCommandHandler : ICommandHandler<CreateAuthorCommand, Author>
    {
        private readonly IUnitOfWork _unitOfWork;

        public AddCommandHandler(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
        }

        public async Task<Result<Author>> Handle(CreateAuthorCommand command)
        {
            var nameResult = Name.Create(command.FirstName, command.LastName);
            var birthDateResult = BirthDate.Create(command.DateOfBirth);
            var mainCategoryResult = Entities.Authors.MainCategory.Create(command.MainCategory);

            var authorResult = Result.Combine(nameResult, birthDateResult, mainCategoryResult)
                                .Map(() => new Author(nameResult.Value, birthDateResult.Value, null, mainCategoryResult.Value));
                
            if (authorResult.IsFailure)
                return Result.Failure<Author>(authorResult.Error);

            await _unitOfWork.AuthorRepository.AddAsync(authorResult.Value);

            await _unitOfWork.SaveChangesAsync();

            return Result.Success(authorResult.Value);
        }
    }
}

这是我的单元测试:

public class CreateAuthorCommandTests
{
    [Fact]
    public void Create_Author_Should_Call_Add_Method_Once() 
    {
        var fixture = new Fixture();
        var command = fixture.Create<CreateAuthorCommand>();
        var mockUnitOfWork = new Mock<IUnitOfWork>();
        var mockHandler = new Mock<ICommandHandler<CreateAuthorCommand, Author>>();

        var result = mockHandler.Object.Handle(command);

        mockUnitOfWork.Verify(x => x.AuthorRepository.AddAsync(It.IsAny<Author>()), Times.Once);
    }
}

当我调试上述测试时,

  1. 我无法进入处理程序方法!
  2. 如何将mockUnitOfWork作为构造函数参数传递给AddCommandHandler

如果我可以通过mockUnitOfWork ,我可以在我的AuthorRepository中验证AddAsync调用。 请协助我做错了什么。

您正在测试处理程序,所以不是这个

var result = mockHandler.Object.Handle(command);

...创建一个实际的 AddCommandHandler 实例并注入它所需的依赖项,即

var mockUnitOfWork = new Mock<IUnitOfWork>();
var handler = new AddCommandHandler(mockUnitOfWork.Object);

当您调用Handle时,您现在将进入您的实现。

如果您想保留 Internal 访问修饰符,您可以使用 InternalsVisibleTo 属性来授予对您的测试项目的访问权限,例如在定义处理程序的项目中执行此操作,

[assembly: InternalsVisibleTo(“UnitTests”)]

https://anthonygiretti.com/2018/06/27/how-to-unit-test-internal-classes-in-net-core-applications/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM