我想弄清楚是否有一些好的做法如何在生产者/消费者场景中对业务逻辑进行单元测试?
我们在应用程序中使用的设计是,几个公共方法接受来自外部系统的请求,将它们放在一个“任务队列”中,然后有另一个线程负责处理队列中的任务。问题是public方法没有做任何复杂的事情,只是将新任务排入队列并设置手动重置事件(以便其他线程可以开始处理新项目)并且所有应该测试的复杂代码都在私人方法。
我知道我可以将这些私有方法更改为内部但我不喜欢这样,因为每个开发人员都可以直接调用这些方法而不是公共方法,从而完全绕过任务队列。
那么有什么方法可以测试这些私有方法吗?也许小型重构或重新设计?感谢
我们使用的设计的骨架:
OrderService:
1)公共方法
public void OrderReceived(OrderDto orderDto, Action<Exception> callback)
{
try
{
taskManager.ProcessWorkItem(() => OrderReceivedImpl(orderDto, callback));
}
catch (Exception ex)
{
Logger.Error(ex);
callback(ex);
}
}
2)我想测试的私有方法:
private void OrderReceivedImpl(OrderDto orderDto, Action<Exception> callback)
{
try
{
// some business logic
callback(null);
}
catch (Exception ex)
{
Logger.Error(ex);
callback(ex);
}
}
TaskManager类:
1)排队任务的方法
public void ProcessWorkItem(Action action)
{
taskQueue.Enqueue(action);
newWorkItemReceived.Set();
}
2)分离线程处理任务的方法:
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;
}
}
}
答案 0 :(得分:1)
如果您不想更改当前实现,请使用模拟框架(如Moq),并创建taskManager
的模拟。您的模拟对象可以设置为调用ProcessWorkItem
只是立即调用操作并允许私有方法保持私有。
答案 1 :(得分:1)
也许将您的业务逻辑注入OrderService
ala战略模式。类似的东西:
public interface IOrderReceiverStrategy
{
void OrderReceived(OrderDto orderDto, Action<Exception> callback);
}
public class OrderReceiverStrategy : IOrderReceiverStrategy
{
public void OrderReceived(OrderDto orderDto, Action<Exception> callback)
{
try
{
// some business logic
callback(null);
}
catch (Exception ex)
{
Logger.Error(ex);
callback(ex);
}
}
}
public class OrderService
{
public OrderService(IOrderReceiverStrategy strategy) { }
public void OrderReceived(OrderDto orderDto, Action<Exception> callback)
{
try
{
taskManager.ProcessWorkItem(() => _strategy.OrderReceived(orderDto, callback));
}
catch (Exception ex)
{
Logger.Error(ex);
callback(ex);
}
}
}
然后,您只需通过单元测试OrderReceiverStrategy
验证您的业务逻辑。
答案 2 :(得分:0)
您应该根据给定的参数测试该私有方法将更改的状态。
如果使用外部资源(数据库,文件系统,其他API:s)的私有方法,你应该抽象它们并作为依赖项传递给类,在单元测试中你可以模拟它们并对模拟的依赖项断言逻辑。 / p>
另一种方法是遵循“单一责任原则”。有了这个原则,班级应该只有一个改变的理由 此刻我看到了下一个原因
因此,您可以将订单处理移到类外部,并将其作为依赖项传递给队列类。
答案 3 :(得分:0)
我会将它们更改为内部并移动到独立库。之后我会做一个可以看到内部的TestClass,并在那里实现一些代理调用这些方法的公共“methodsExtensionsTesting”,并在你的unitTests中调用它们,这样你就可以直接检查它们。