简体   繁体   中英

Unit Testing NAudio with ManualResetEvent Locks Up Test

Alright, I'm trying to unit test NAudio against a wrapper I created for a recording session, here is the code that starts and stops a recording session ...

public void StartRecording(string claimNo, string ip_no, string ip_name)
{
    if (this.IsRecording)
    {
        return;
    }

    this.Recordings.Add(new RecordingTrack(claimNo, ip_no, ip_name));
    if (this.MicrophoneLevel == default(float))
    {
        this.MicrophoneLevel = .75f;
    }

    _aggregator.Reset();

    _input = new WaveIn();
    _input.WaveFormat = _waveFormat;

    _input.DataAvailable += (s, args) =>
        {
            _writer.Write(args.Buffer, 0, args.BytesRecorded);
            byte[] buffer = args.Buffer;
            for (int index = 0; index < args.BytesRecorded; index += 2)
            {
                short sample = (short)((buffer[index + 1] << 8) | buffer[index + 0]);
                float sample32 = sample / 32768f;
                _aggregator.Add(sample32);
            }

            if (this.DataAvailable != null)
            {
                this.DataAvailable(s, args);
            }

            if (!this.IsRecording)
            {
                _writer.Close();
                _writer.Dispose();
                _writer = null;
            }
        };
    _input.RecordingStopped += (s, args) =>
        {
            _input.Dispose();
            _input = null;

            if (this.RecordingStopped != null)
            {
                this.RecordingStopped(s, args);
            }
        };

    _writer = new WaveFileWriter(this.CurrentRecording.FileName, _input.WaveFormat);

    _input.StartRecording();
    this.IsRecording = true;
}

public void StopRecording()
{
    if (!this.IsRecording)
    {
        return;
    }

    this.CurrentRecording.Stop();

    this.IsRecording = false;
    _input.StopRecording();
}

... and below is my unit test. I'm using a ManualResetEvent to assert the success of the event being fired and it's declared like this ...

private ManualResetEvent _eventRaised = new ManualResetEvent(false);

... however, the issue is that the test below simply locks up and the event is never fired. Can you confirm that the issue is that the WaitOne is not allowing the event to fire because it's locking the same thread?

bool success = false;
_eventRaised.Reset();

var target = new RecordingSession();
target.StartRecording("1", "01", "Test Name");

target.RecordingStopped += (s, args) =>
    {
        success = (target.CurrentRecording.Duration.TotalSeconds > 4);
        _eventRaised.Set();
    };

Thread.Sleep(4000);
target.StopRecording();

_eventRaised.WaitOne();

Assert.IsTrue(success);

And if so, can you help me with this test? I need some enlightenment.

I've used the ManualResetEvent many times to test events on other classes and it's worked, but something is different here.

It is possible that the event is fired before you have connected to it if the _input member is working in its own thread. Hence, the manual reset event will never get set, causing it to wait forever/lock up your unit test.

So perhaps try re-order your definition to:

target.RecordingStopped += (s, args) =>     
{         
    success = (target.CurrentRecording.Duration.TotalSeconds > 4);         
    _eventRaised.Set();     
};

target.StartRecording("1", "01", "Test Name"); 

You'll never get an event because the default constructor of WaveIn uses windowed callbacks, and you are not running your unit test on a GUI thread. You should use WaveInEvent instead to work on a non-gui thread. In the very latest NAudio code an InvalidOperationException should be thrown to prevent you from making this mistake.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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