简体   繁体   English

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

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

I'm learning and practicing CQRS and Unit Test in C#.我正在 C# 中学习和练习 CQRS 和单元测试。 I need to know how to unit test Command Handlers in CQRS.我需要知道如何在 CQRS 中对命令处理程序进行单元测试。

Here is my CreateAuthorCommand :这是我的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);
        }
    }
}

Here is my Unit Test:这是我的单元测试:

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);
    }
}

When I debug the above test,当我调试上述测试时,

  1. I'm not able to step into Handler Method!!我无法进入处理程序方法!
  2. How to pass mockUnitOfWork as constructor parameter to AddCommandHandler ?如何将mockUnitOfWork作为构造函数参数传递给AddCommandHandler

If I can pass mockUnitOfWork , the I can verify the AddAsync call inside my AuthorRepository .如果我可以通过mockUnitOfWork ,我可以在我的AuthorRepository中验证AddAsync调用。 Please assist on what I'm doing wrong.请协助我做错了什么。

You are testing the handler, so instead of this您正在测试处理程序,所以不是这个

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

...create an actual instance of AddCommandHandler and inject the dependencies it requires, ie ...创建一个实际的 AddCommandHandler 实例并注入它所需的依赖项,即

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

When you call in to Handle , you'll now be stepping into your implementation.当您调用Handle时,您现在将进入您的实现。

If you want to keep the Internal access modifier, you can use InternalsVisibleTo attribute to grant access to your test project, eg do this in your project that defines the Handler,如果您想保留 Internal 访问修饰符,您可以使用 InternalsVisibleTo 属性来授予对您的测试项目的访问权限,例如在定义处理程序的项目中执行此操作,

[assembly: InternalsVisibleTo(“UnitTests”)]

https://anthonygiretti.com/2018/06/27/how-to-unit-test-internal-classes-in-net-core-applications/ 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