Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

I have inherited a small project and want to extend it and stabilize it at the same time by writing Unit Tests for all the new code I am adding. The first class, TypedAudioCreator, creates audio files and this turned out to be very easy to test first and write code for second.

However, when it came time to write TypedAudioPlayer, I had no idea how I could test it. It's a very small class focusing on the very basics of playing sound:

public class TypedAudioFilePlayer
{
    public event StartedPlayingHandler StartedPlaying;
    public event StoppedPlayingHandler StoppedPlaying;

    public readonly int TimeBetweenPlays;

    private Queue<TypedAudioFile> _playlist = new Queue<TypedAudioFile>(); 

    public TypedAudioFilePlayer(int timeBetweenPlays)
    {
        TimeBetweenPlays = timeBetweenPlays;
    }

    public void AddFile(TypedAudioFile file)
    {
        _playlist.Enqueue(file);
    }

    public void StartPlaying()
    {
        ThreadPool.QueueUserWorkItem(ignoredState =>
        {
            while (_playlist.Count > 0)
            {
                var audioFile = _playlist.Dequeue();

                if (StartedPlaying != null)
                    StartedPlaying(audioFile);

                audioFile.SoundPlayer.PlaySync();
                audioFile.SoundPlayer.Dispose();

                if (StoppedPlaying != null)
                    StoppedPlaying(audioFile);
            }
        });
    }

    public void StopPlaying()
    {
        if (StoppedPlaying != null)
            StoppedPlaying(null);
    }
}

I'm still very new at TDD, but I realize the benefits of the practice and would like to try and get better at it. I have written Code first, no tests here, but that was just me being too lazy to properly think of the TDD way of solving it. The question I have is, how should/could I test this class?

share|improve this question
2  
Aren't there mocking-frameworks in C#? This should solve your problems. –  user43552 Feb 20 '12 at 7:09
2  
@user43552: That would just be testing a mock... this scenario is intended to test the audio player. –  Steve Evers Feb 20 '12 at 7:35
5  
I'm not familiar with how to do audio in C#, but it seems to me that you need to refactor this class so that you can inject a mock in place of audioFile.SoundPlayer. Then test with this mock, and verify that PlaySync and Dispose are called at the right places. You also want to be able to inject the StartedPlayingHandler and the StoppedPlayingHandler if possible. –  David Wallace Feb 20 '12 at 7:49
2  
Shouldn't this be on stackoverflow? –  Amr H. Abdel Majeed Feb 20 '12 at 11:15
1  
@AmrH.AbdelMajeed - why? Just because it has code? –  ChrisF Feb 20 '12 at 13:56

3 Answers 3

There are many things "on the edges" of most systems that cannot adequately be unit tested. For example, anything that produces graphics or sound. For these kinds of systems, you are probably best off with manual testing. Even given an automated solution, these outputs are meant for human perception. The only way to know that you are producing the desired effect is to have a human interact with them.

It may be possible to perform a manual test, then record the output of that manual test and create an automated test that ensures that the output does not change. Be warned though that tests like these are incredibly fragile: any change to the underlying code may require a repeat of the manual test and then creating a new recording for the automated test.

share|improve this answer
1  
+1 for 'There are many things "on the edges" of most systems that cannot adequately be unit tested.' –  user23157 Feb 20 '12 at 9:24
2  
This answer is highly misleading. Just because the final output device for audio code is often a pair of speakers, it doesn't mean that audio code cannot be unit tested or that it needs to be tested perceptually. All audio software has a digital output that can be measured and compared to an expected output. One approach to unit testing audio can be found in this paper –  Jamie Bullock Nov 10 '14 at 10:26

It's obviously difficult to automatically test that the audioplayer really plays audio, but you can create useful unit tests anyway. For example, you can test that StartPlaying() causes the StartedPlaying event, and StopPlaying() causes the StoppedPlaying event. You can test the behavour when trying to play an empty playlist, or a null playlist. You can test that AddFile really adds the file to the playlist. You can test that after playing an audio file, it is removed from the playlist (if that is desired). Maybe there are cornercases for broken audio files etc. too that deserve testing.

Having unit tests for those things, you can be sure that the class behaves well, i.e. meets its contracts. If it does, but still plays no sound, that's relatively easy to catch in manual tests.

share|improve this answer

Keep in mind that there is a difference between Unit Testing, which is the act of writing small tests that test individual units of your code, and Automated Test Runners which run your unit tests, usually as part of the build process or some kind of continuous integration system.

Unit testing is commonly automated, but may still be performed manually. The IEEE does not favor one over the other. The objective in unit testing is to isolate a unit and validate its correctness. A manual approach to unit testing may employ a step-by-step instructional document.

(http://en.wikipedia.org/wiki/Unit_testing#Techniques)

You can easily write a unit test to test that an audio player component plays audio correctly:

  1. Make sure your speakers are working and the volume is turned up.
  2. Go to /my/test/folder.
  3. Execute myTestRunner audioPlayerTest.script.thingee.
  4. You should hear Beethoven's 5th Symphony play for 15 seconds.
  5. If you heard nothing, the audio played more or less than 15 seconds, or was distorted in any way, the test failed. Otherwise, the test passed.

What you can't easily do is include that test in an automated testing system. Automated testing is a particular implementation of unit testing, but it isn't the only implementation.

See also: http://stackoverflow.com/questions/1877118/is-unit-testing-always-automated

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.