在 .Net Core 中为单元测试编写更好的装置 GetClientsInteractorTest.csGetClientsInteractorTestsFixture.cs

如何解决在 .Net Core 中为单元测试编写更好的装置 GetClientsInteractorTest.csGetClientsInteractorTestsFixture.cs

我对 .Net Core 中的单元测试还很陌生。我正在为 Interactor 类编写单元测试,该类的职责是使用 Client 依赖项通过电子邮件名称获取IClientGateway。我使用过 XUnitMoq.AutoMockFluentAssertions

GetClientsInteractorTest.cs

[Trait("Clients","GetClientsInteractor")]
[Collection(nameof(GetClientsInteractorTestsCollectionFixture))]
public class GetClientsInteractorTests
{
    private readonly GetClientsInteractorTestsFixture fixture;

    public GetClientsInteractorTests(GetClientsInteractorTestsFixture fixture) =>
        this.fixture = fixture;

    [Theory(displayName = "should return clients in clientsGateway")]
    [MemberData(nameof(GetClientsInteractorTestsFixture.Params),MemberType = typeof(GetClientsInteractorTestsFixture))]
    public async Task ShouldReturnClients(IEnumerable<Client> mockedClients,CancellationTokenSource cancellationTokenSource,GetClientsRequest request,GetClientsResponse expectedResponse)
    {
        // Arrange
        fixture.Mocker.GetMock<IClientGateway>()
            .Setup(ClientGateway => ClientGateway.GetByNameAsync(request.Name,cancellationTokenSource.Token))
            .ReturnsAsync(mockedClients.Where(client => client.Name.Equals(request.Name)))
            .Verifiable();
        fixture.Mocker.GetMock<IClientGateway>()
            .Setup(ClientGateway => ClientGateway.GetByEmailAsync(request.Email,cancellationTokenSource.Token))
            .ReturnsAsync(mockedClients.Where(client => client.Email.Equals(request.Email)))
            .Verifiable();
        // Act
        GetClientsResponse actualResponse =
            await fixture.Mocker.CreateInstance<GetClientsInteractor>()
            .Handle(request,cancellationTokenSource.Token);
        // Assert
        if(request.Name != null)
            fixture.Mocker.GetMock<IClientGateway>()
                .Verify(mock => mock.GetByNameAsync(request.Name,cancellationTokenSource.Token),Times.Once(),"GetByNameAsync was not called");
        else if (request.Email != null)
            fixture.Mocker.GetMock<IClientGateway>()
                .Verify(mock => mock.GetByEmailAsync(request.Email,"GetByEmailAsync was not called");
        actualResponse.Should()
            .Be(expectedResponse);
    }
}

GetClientsInteractorTestsFixture.cs

public class GetClientsInteractorTestsFixture
{
    public AutoMocker Mocker = new AutoMocker(MockBehavior.Strict);

    public static IEnumerable<Client> mockedClients = new Client[] {
            new Client()
            {
                ClientId = 1,Name = "Victor",Email = "someEmail@someProvider.com"
            },};

    public static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

    public static IEnumerable<object[]> Params = new[]
    {
        new object[]
        {
            mockedClients,cancellationTokenSource,new GetClientsRequest(),new GetClientsResponse()
        },new object[]
        {
            mockedClients,new GetClientsRequest(){ Name = "Victor" },new GetClientsResponse(){ Clients = new List<ClientDto>()
                {
                    new ClientDto()
                    {
                        Id = 1,Email = "someEmail@someProvider.com"
                    }
                }
            }
        },new GetClientsRequest(){ Email = "someEmail@someProvider.com"},};
}

单元测试本身 (ShouldReturnClients) 起初非常简单,但它需要 4 个参数(加上 AutoMocker)作为测试装置,可在 GetClientsInteractorTestsFixture 中找到。有没有更好的方法通过减少重复来制作这个测试装置?也许使用类似 AutoFixture 的东西?

解决方法

简短的回答是 - 是的,AutoFixture 可以帮助您减少样板文件并保持测试干燥。 下面是您使用 AutoFixture 进行的测试可能看起来像什么。 有关使用 AutoFixture 的更多详细信息,您可以访问 documentation,查看 Pluralsight course,在 Mark Seeman 的 blog 上阅读 AutoFixture,或在 AutoFixture 的 GitHub Q&A section 上寻求帮助。

[Theory]
[MemberAutoDomainData(nameof(GetClientsInteractorTestsFixture.Params))]
public async Task ReturnsExpectedResponse(
    GetClientsRequest request,GetClientsResponse expectedResponse,GetClientsInteractor sut)
{
    var actual = await sut.Handle(request,default);

    actual.Should().Be(expectedResponse);
}

[Theory]
[MemberAutoDomainData(nameof(GetClientsInteractorTestsFixture.ParamsWithName))]
public async Task RequestsClientsByNameWhenRequestContainsName(
    [Frozen] Mock<IClientGateway> gateway,GetClientsRequest request,GetClientsInteractor sut)
{
    await sut.Handle(request,default);

    gateway.Verify(
        x => x.GetByNameAsync(request.Name,It.IsAny<CancellationToken>()),Times.Once(),"GetByNameAsync was not called");
}

[Theory]
[MemberAutoDomainData(nameof(GetClientsInteractorTestsFixture.Params))]
public async Task RequestsClientsByNameWhenRequestNameEmpty(
    [Frozen] Mock<IClientGateway> gateway,default);

    gateway.Verify(
        x => x.GetByEmailAsync(request.Email,"GetByEmailAsync was not called");
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?