简体   繁体   English

测试之间的共享上下文

[英]Shared context between tests

I have following code: 我有以下代码:

public class Batcher<TPayload> : IBatcher<TPayload>
{    
    private static readonly BufferBlock<BatchElement<TPayload>> BufferBlock = new BufferBlock<BatchElement<TPayload>>(new DataflowBlockOptions
    {
        EnsureOrdered = true
    });

    private readonly TransformBlock<BatchElement<TPayload>, BatchElement<TPayload>> BufferInterceptor;
    private readonly TransformBlock<BatchElement<TPayload>, BatchElement<TPayload>> TimeoutInterceptor;

    public EventsBatcher(int size, int interval, IMagicService magicService, ILogger<Batcher<TPayload, TStrategy>> logger)
    {
        BufferInterceptor =
            new TransformBlock<BatchElement<TPayload>, BatchElement<TPayload>>(x =>
            {
                logger.LogInformation($"Get a message with value: {x}");
                return x;
            });

        TimeoutInterceptor =
            new TransformBlock<BatchElement<TPayload>, BatchElement<TPayload>>(x =>
            {
                logger.LogInformation($"Move out from transformation block with a value: {x}");
                return x;
            });

        var batchBlock = new BatchBlock<BatchElement<TPayload>>(size, new GroupingDataflowBlockOptions()
        {
            EnsureOrdered = true
        });

        var timer = new Timer(async _ =>
        {
            try
            {
                batchBlock.TriggerBatch();
                var data = await batchBlock.ReceiveAsync();
                if (!data.Any() && data.SomeLogic())
                     return;

                await magicService.PushMessageAsync(batchElement.Payload);
            }
            catch (Exception e)
            {
                logger.LogError($"Error occurs while trying to invoke action on batch", e);
            }
        }, null, 0, 500);

        var timeoutBlock = new TransformBlock<BatchElement<TPayload>, BatchElement<TPayload>>(v =>
        {
            timer.Change(interval, Timeout.Infinite);
            return v;
        });

        TimeoutInterceptor.LinkTo(batchBlock);
        timeoutBlock.LinkTo(TimeoutInterceptor);
        BufferInterceptor.LinkTo(timeoutBlock);
        BufferBlock.LinkTo(BufferInterceptor);
    }

    public async Task<Result<Unit>> SendAsync(BatchElement<TPayload> msg, CancellationToken token = new CancellationToken())
    {
        try
        {
            var result = await BufferBlock.SendAsync(msg, token);
            return result
                ? ResultFactory.CreateSuccess()
                : ResultFactory.CreateFailure<Unit>("Message was refused by queue");
        }
        catch (Exception e)
        {
            return ResultFactory.CreateFailure<Unit>(e.Message);
        }
    }     
}

Which responsibility is to evaluate somehow data every x milliseconds. 哪个职责是每x毫秒以某种方式评估数据。 I try to write unit tests to that to be sure that everything works fine. 我尝试为此编写单元测试,以确保一切正常。 Those tests are here: 这些测试在这里:

public class BatcherTests
{
    public EventsBatcher<int> Initialize(Dictionary<DateTime, int> output)
    {
        var busMock = new Mock<IMagicService>();
        busMock.Setup(x => x.PushMessageAsync(It.IsAny<int>()))
            .Callback<Data>((data) =>
            {
                output.Add(DateTime.Now, data);
            }).Returns(Task.CompletedTask);

        var loggerMock = new Mock<ILogger<Batcher<int>>>();
        return new Batcher<int>(
            2, 
            5000, 
            busMock.Object,
            loggerMock.Object
        );
    }

    [Fact]
    public async Task Batcher_ShouldRemoveDuplicatedMessages()
    {
        var output = new Dictionary<DateTime, int>();
        var batcher = Initialize(output);
        var first = await batcher.SendAsync(new MockEvent { Payload = 1 });
        var second = await batcher.SendAsync(new MockEvent { Payload = 1 });

        (first.IsSuccess && second.IsSuccess).ShouldBeTrue();
        while (output.Count != 2)
        {
        }

        output.Count.ShouldBe(2);
        output.First().Value.ShouldBe(1);
        output.Last().Value.ShouldBe(1);
        output.Clear();
    }

    [Fact]
    public async Task Batcher_WhenSizeIsSetTo2AndWeSend3Items_ReturnTwoBatchedItemsWithDateIntervalPlusMinus5000msAndAllSendRequestsEndsWithSuccess()
    {
        var output = new Dictionary<DateTime, int>();
        var batcher = Initialize(output);

        var first = await batcher.SendAsync(new MockEvent { Payload = 1 });
        var second = await batcher.SendAsync(new MockEvent { Payload = 1 });
        var third = await batcher.SendAsync(new MockEvent { Payload = 1 });

        (first.IsSuccess && second.IsSuccess && third.IsSuccess).ShouldBeTrue();
        while (output.Count != 2) //never ends because there are already two elements in output dictionary
        {
        }

        output.Count.ShouldBe(2);
        output.First().Value.ShouldBe(2);
        output.Last().Value.ShouldBe(1);

        var interval = (output.Last().Key - output.First().Key).TotalSeconds;

        (interval >= 4.5d && interval <= 5.5d).ShouldBeTrue();
        output.Clear();
    }
}

But the strange thing is that when I run them separately they end up with a success status. 但是奇怪的是,当我分别运行它们时,它们最终会获得成功状态。 But when I run them all together one of them seems to stuck. 但是当我将它们全部运行在一起时,其中一个似乎卡住了。 This is because a dictionary which is passed to a logic method has 2 elements inside while starting a test. 这是因为传递给逻辑方法的字典在开始测试时内部有2个元素。 I don't see here a possibility of shared context since stub class is created at the beginning of test cases, the same with a dictionary. 我在这里看不到共享上下文的可能性,因为stub类是在测试用例的开头创建的,与字典相同。 Is there something that I missing? 我有什么想念的吗? I also try to split those test cases to separe classes but the same behavior occurs. 我还尝试将这些测试用例拆分为单独的类,但是会发生相同的行为。

There is shared stated, but it is not in the test (directly). 有共享声明,但未在测试中(直接)。

Your BufferBlock is declared as static in the class Batcher<TPayload> . 您的BufferBlockBatcher<TPayload>类中声明为static的。 There is your shared state. 有您的共享状态。

private static readonly BufferBlock<BatchElement<TPayload>> BufferBlock = new BufferBlock<BatchElement<TPayload>>(new DataflowBlockOptions
{
    EnsureOrdered = true
});

When multiple tests are executed that shared block is linked to the other blocks multiple times. 当执行多个测试时,该共享块将多次链接到其他块。

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

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