另一个线程

时间:2016-09-15 12:32:46

标签: c# unit-testing nunit justmock

public class Composer
{
    private Task _ComposerTask;    
    private ConcurrentQueue<IValue> _Values;   
    public bool IsConnected { get; }

    // Other dependencies
    private IClient _Client;
    private IWriter _Writer

    public Task async ConnectAsync()
    {
        this.IsConnected = await _Client.ConnectAsync();
        _ComposerTask = Task.Run(() => this.Start());
    }

    private void Start()
    {
        while(this.IsConnected)
        {
            IValue value;
            if(_Values.TryDequeue(out value) == false)
                continue;

            _Writer.Write(value);
        }
    }

    public void Send(IValue value)
    {
        _Values.Enqueue(value);
    }
}

成功连接Composer类异步执行Start方法(在另一个线程上)。
Start方法检查值队列,如果值存在则向前发送。

我在测试Send方法时遇到的问题。

[Test]
public void Send_ValidMessage_ExecuteWriteMethodWithGivenValue()
{
    // Arrange
    var fakeValue = Mock.Create<IValue>();
    var fakeWriter = Mock.Create<IWriter>();
    var fakeClient = Mock.Create<IClient>();

    Mock.Arrange(() => fakeClient.ConnectAsync().Returns(CompletedTask);

    var composer = new Composer(fakeClient, fakeWriter);

    // for (int i = 0; i < 10; i++)
    // {
    //     composer.Send(Mock.Create<IValue>());
    // }

    composer.ConnectAsync().Wait();

    // Act
    composer.Send(fakeValue);

    // Assert
    Mock.Assert(() => fakeWriter.Write(fakeValue), Occurs.Once());
}

通过评论for loop测试。但是如果执行for loop并且在添加预期值之前内部队列将填充10个值,则测试将失败并显示消息:预期至少一次,但发生0次

据我所知,断言发生在值被另一个线程排队之前,但是如何测试这种行为?

2 个答案:

答案 0 :(得分:0)

你需要建立某种&#34;加入&#34;。这样的事情就足够了:

p {
  font-size: 8px;
}

请注意,您还应该在生产代码中使用它。如果您的代码最终没有看到<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <p>A</p> <p>B</p> <p>C</p> <p>D</p> <p>E</p> <button id="reset">Reset</button>,那么public Task JoinAsync() { this.IsConnected = false; return _ComposerTask; } 引发的任何异常都会被默默地吞没。

答案 1 :(得分:0)

我提出的解决方案是重新设计Composer类或更具体的更改Send方法异步:

public Task SendAsync(IValue value)
{

}

背后的想法是返回Task,当在“背景”主题上向前组合给定值时,它将完成。

单元测试只需要await,直到任务完成并断言正确执行。

[Test]
public async Task SendAsync_ValidMessage_ExecuteWriteMethodWithGivenValue()
{
    // Arrange
    var composer = TestFactory.GenerateComposer();

    // var tasks = new List<Task>();
    // for (int i = 0; i < 10; i++)
    // {
    //     tasks.Add(composer.SendAsync(Mock.Create<IValue>()));
    // }

    await composer.ConnectAsync();

    // Act
    await composer.SendAsync(fakeValue);

    // Assert
    Mock.Assert(() => fakeWriter.Write(fakeValue), Occurs.Once());
}

即使没有在for loop中添加额外的值,我的原始单元测试也没有成功。如果多次运行,则偶尔测试失败。 我认为原因是线程池的“不可预测”工作。

我仍然不确定如何处理需要在启动它的实例的整个生命周期内运行的Task,但这将是另一个问题。