I am trying to figure out whether there is some good practice how to unit test business logic in producer/consumer scenario?
Design that we use in our app is that several public methods accept requests from external system, put them in one "task queue" and then there is another thread which is responsible for processing tasks from queue. The problem is that the public method doesn't do anything complex, just enqueue new task to the queue and set manual reset event (so that the other thread can start to process new item) and all the complex code that should be tested is in private methods.
I know that I can change these private method to internal but I don't like this because then every developer could just call directly these methods instead the public ones and thus bypass the task queue completely.
So is there any way how test these private methods? Maybe small refactoring or redesign? Thanks
Skeleton of the design we use:
OrderService:
1) Public method
public void OrderReceived(OrderDto orderDto, Action<Exception> callback)
{
try
{
taskManager.ProcessWorkItem(() => OrderReceivedImpl(orderDto, callback));
}
catch (Exception ex)
{
Logger.Error(ex);
callback(ex);
}
}
2) Private method that I would like to test:
private void OrderReceivedImpl(OrderDto orderDto, Action<Exception> callback)
{
try
{
// some business logic
callback(null);
}
catch (Exception ex)
{
Logger.Error(ex);
callback(ex);
}
}
TaskManager class:
1) Method for enqueuing tasks
public void ProcessWorkItem(Action action)
{
taskQueue.Enqueue(action);
newWorkItemReceived.Set();
}
2) Separate thread's method for processing tasks:
private void ProcessWorkItemQueue()
{
while (true)
{
var waitResult = WaitHandle.WaitAny(new WaitHandle[] { newWorkItemReceived, stopEventReceived });
if (waitResult == 0)
{
while (true)
{
if (taskQueue.Count == 0) break;
Action action;
taskQueue.TryDequeue(out action);
try
{
action.Invoke();
}
catch (Exception ex)
{
Logger.Error(ex);
}
if (stopEventReceived.WaitOne(1)) return;
}
}
else
{
return;
}
}
}