开发者

Problem when Unit-testing multi threaded code

I have implemented a Pipe class that internally uses a BlockingQueue to store the data it receives.

There 开发者_如何学Pythonare two situations when the BlockingQueue will block the calling thread:

  1. The calling thread makes a call to Dequeue() and the queue is empty. It will block the thread until there is an item to retrieve.
  2. The calling thread makes a call to Enqueue() and the queue is full. It will block the thread until there is space again to insert the data.

My initial idea was that instead of having the Pipe class instantiate the BlockingQueue, I'd pass an instance of an IQueue to it by constructor injection. That way, when testing, I'd pass it an instance of a NonBlockingQueue, so I wouldn't have to bother with threading problems (when I'm doing Unit-tests, both for the Pipe class and for other classes that use Pipes I'd like to just add things to the queues and not having to think if they are full already and things like that).

The trouble is that when doing this, I'm actually making my Pipe behave in 2 totally different ways, depending on the kind of IQueue instance I'm passing to it:

  • In a BlockingQueue, if the queue is empty and you try to retrieve something from it, it'll block until it gets something. In a NonBlockingQueue it'll just throw up an exception.

  • In a BlockingQueue, if the queue is full and you try to add something, it will wait until someone dequeues an element and there is space again. A NonBlockingQueue version will either throw up an FullQueueException or will allow an "infinite" number of elements.

That is, there is no "single contract". I think this approach is definitely wrong.

What is a more apropriate approach to this?

Edit to Mitch:

This is being used to implement a Pipe&Filter system: each Filter has an input and output pipes. Each filter then is implemented with code of the form

char c;
while ((c = inputPipe.ReadChar()) != STREAM_TERMINATOR) { 
//I don't have to care 
//if right now there is any data. I know that if there isn't, 
//the thread will block and this will continue after there is some.

    ...do processing
    outputPipe.WriteChar(something);
}
outputPipe.WriteChar(STREAM_TERMINATOR);

so I guess yes, having blocking pipes / queues is the behaviour I want.


The idea of unit testing is that you test small portions of code, and with a lot of those you eventually test all your code. There is a reason it is broken down in pieces, testing one piece at a time is easier than testing everything simultaneously. In the code you use the BlockingQueue, and in the testing you use a NonBlockingQueue, which introduces all kinds of challenging aspects and this defeats the purpose of unit testing... In the tests you should simplify, not complicate. So why not just use a BlockingQueue there too ? You state that the threading might be a problem, but at least use a simple implementation of IQueue which from the outside works exactly like a BlockingQueue, but without the threading problems. In the unit tests you should be able to provide an instance of such in IQueue which doesn't throw exceptions. For example, instead of when you'd normally throw an exception since the queue is empty, just come up with a new item. That is allowed in tests....


Your idea of having a constructor injected implementation of IQueue is correct.

Now what do you want to unit test here?

  1. IQueue implementation
  2. Pipe responsibility (apart from interacting with IQueue implementation)
  3. Interaction of Pipe and IQueue implementation

You want to focus on point #3. I think you need to think of responsibilities here. Whose responsibility is it to ensure that a queue is blocked or not. It is the responsibility of a IQueue implementation and not Pipe. So, IQueue contract will just have an 'action' (a method call) that happens when we have an exceptional situation (dequeuing from an empty queue or adding to a full queue). You want to unit test this interaction, which means just testing whether the action method gets called in the exceptional situation.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜