Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 测试之间的共享上下文_C#_Timer_Task Parallel Library_Xunit - Fatal编程技术网

C# 测试之间的共享上下文

C# 测试之间的共享上下文,c#,timer,task-parallel-library,xunit,C#,Timer,Task Parallel Library,Xunit,我有以下代码: public class Batcher<TPayload> : IBatcher<TPayload> { private static readonly BufferBlock<BatchElement<TPayload>> BufferBlock = new BufferBlock<BatchElement<TPayload>>(new DataflowBlockOptions {

我有以下代码:

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);
        }
    }     
}
公共类批处理程序:IBatcher
{    
私有静态只读缓冲块缓冲块=新缓冲块(新DataflowBlockOptions
{
重新排序=真
});
专用只读转换块缓冲拦截器;
专用只读TransformBlock TimeoutInterceptor;
公共事件记录器(整数大小、整数间隔、IMagicService magicService、ILogger记录器)
{
缓冲拦截器=
新转换块(x=>
{
logger.LogInformation($“获取值为:{x}的消息”);
返回x;
});
定时接收器=
新转换块(x=>
{
logger.LogInformation($“从转换块移出,值为:{x}”);
返回x;
});
var batchBlock=new batchBlock(大小,新分组DataFlowBlockOptions()
{
重新排序=真
});
变量计时器=新计时器(异步)
{
尝试
{
batchBlock.TriggerBatch();
var data=await batchBlock.ReceiveAsync();
如果(!data.Any()&&data.SomeLogic())
返回;
等待magicService.PushMessageAsync(batchElement.Payload);
}
捕获(例外e)
{
logger.LogError($“尝试调用批处理操作时出错”,e);
}
},空,0,500);
var timeoutBlock=新转换块(v=>
{
timer.Change(间隔、超时、无限);
返回v;
});
TimeoutInterceptor.LinkTo(批块);
timeoutBlock.LinkTo(TimeoutInterceptor);
BufferInterceptor.LinkTo(超时块);
链接到(缓冲拦截器);
}
公共异步任务SendAsync(BatchElement msg,CancellationToken token=new CancellationToken())
{
尝试
{
var result=await BufferBlock.SendAsync(消息,令牌);
返回结果
?ResultFactory.CreateSuccess()
:ResultFactory.CreateFailure(“消息被队列拒绝”);
}
捕获(例外e)
{
返回ResultFactory.CreateFailure(e.Message);
}
}     
}
其职责是每隔x毫秒评估一次数据。我尝试编写单元测试来确保一切正常。这些测试如下:

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();
    }
}
公共类批处理测试
{
公共事件记录器初始化(字典输出)
{
var busMock=new Mock();
Setup(x=>x.PushMessageAsync(It.IsAny())
.回调((数据)=>
{
Add(DateTime.Now,data);
}).Returns(Task.CompletedTask);
var loggerMock=new Mock();
返回新批处理程序(
2.
5000, 
busMock.对象,
loggerMock,目标
);
}
[事实]
公共异步任务批处理程序\u应删除重复消息()
{
var输出=新字典();
var批处理程序=初始化(输出);
var first=await batcher.SendAsync(新MockEvent{Payload=1});
var second=await batcher.SendAsync(新MockEvent{Payload=1});
(first.issucess&&second.issucess).ShouldBeTrue();
while(output.Count!=2)
{
}
输出.计数.应为(2);
output.First().Value.should1;
output.Last().Value.应为(1);
output.Clear();
}
[事实]
公共异步任务批处理程序\u当设置为2和Wesend3项时\u返回两个BatchEditemSwithDate IntervalplusMinus5000MsandallSendRequestSendSwithSuccess()
{
var输出=新字典();
var批处理程序=初始化(输出);
var first=await batcher.SendAsync(新MockEvent{Payload=1});
var second=await batcher.SendAsync(新MockEvent{Payload=1});
var third=await batcher.SendAsync(新MockEvent{Payload=1});
(first.issucess&&second.issucess&&third.issucess)。ShouldBeTrue();
while(output.Count!=2)//永不结束,因为输出字典中已经有两个元素
{
}
输出.计数.应为(2);
output.First().Value.should应为(2);
output.Last().Value.应为(1);
var interval=(output.Last().Key-output.First().Key).TotalSeconds;

(间隔>=4.5d&&interval有共享声明,但不在测试中(直接)

您的
BufferBlock
在类
Batcher
中声明为
static
。这是您的共享状态

private static readonly BufferBlock<BatchElement<TPayload>> BufferBlock = new BufferBlock<BatchElement<TPayload>>(new DataflowBlockOptions
{
    EnsureOrdered = true
});
private static readonly BufferBlock BufferBlock=new BufferBlock(new DataflowBlockOptions
{
重新排序=真
});

当执行多个测试时,该共享块会多次链接到其他块。

@PeterBons啊,好主意!我想我删除了Resharper提示的所有静态字段。您能添加一个指向确切问题的答案,以便我接受它吗?