jeudi 15 septembre 2016

Unit testing methods on another thread

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

When connected successfully Composer class execute Start method asynchronously(on another thread).
Start method check queue of values and send it forward if value exists.

My problem in testing a Send method.

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

With commented for loop test passed. But if for loop executed and inner queue will be filled with even 10 values before expected value added, then test fails with message: expected at least once, nut occurs 0 times.

As I understand assertion occurs before value was queued by another thread, but how this kind of behavior can be tested?

Aucun commentaire:

Enregistrer un commentaire