C# C-如何在生产者/消费者场景中对私有方法进行单元测试?
我试图弄清楚,在生产者/消费者场景中,是否有一些好的实践方法来单元测试业务逻辑 我们在应用程序中使用的设计是,几个公共方法接受来自外部系统的请求,将它们放在一个任务队列中,然后有另一个线程负责处理队列中的任务。问题在于,public方法不做任何复杂的事情,只需将新任务排入队列并设置手动重置事件,这样其他线程就可以开始处理新项目,所有需要测试的复杂代码都在私有方法中 我知道我可以将这些私有方法更改为内部方法,但我不喜欢这样,因为这样每个开发人员都可以直接调用这些方法而不是公共方法,从而完全绕过任务队列 那么有没有办法测试这些私有方法呢?也许是小规模的重构或重新设计?谢谢 我们使用的设计框架: 订单服务: 1公共方法C# C-如何在生产者/消费者场景中对私有方法进行单元测试?,c#,multithreading,unit-testing,C#,Multithreading,Unit Testing,我试图弄清楚,在生产者/消费者场景中,是否有一些好的实践方法来单元测试业务逻辑 我们在应用程序中使用的设计是,几个公共方法接受来自外部系统的请求,将它们放在一个任务队列中,然后有另一个线程负责处理队列中的任务。问题在于,public方法不做任何复杂的事情,只需将新任务排入队列并设置手动重置事件,这样其他线程就可以开始处理新项目,所有需要测试的复杂代码都在私有方法中 我知道我可以将这些私有方法更改为内部方法,但我不喜欢这样,因为这样每个开发人员都可以直接调用这些方法而不是公共方法,从而完全绕过任务
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 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;
}
}
}
您应该测试私有方法将根据给定参数更改的状态 如果该私有方法使用外部资源数据库、文件系统和其他API,那么您应该将它们抽象并作为依赖项传递给类,在单元测试中,您可以对它们进行模拟,并根据模拟的依赖项断言逻辑 另一种方法是遵循单一责任原则。有了这个原则,班级应该只有一个改变的理由。 此时此刻,我看到了下一个原因 当您将更改处理收到的订单的业务逻辑时,您需要更改您的类。 当您更改处理队列、集合或其他方式中不同订单的方式时,需要更改类。
因此,您可以将订单处理移到类之外,并将其作为依赖项传递给队列类。我将它们更改为内部,并移到独立库。之后,我将做一个TestClass,它可以查看内部结构并在那里实现一些公共的methodsExtensionsTesting,代理调用这些方法,并在unitTests中调用它们,这样您就可以直接检查它们了 如果不想更改当前实现,请使用模拟框架,如Moq,并创建taskManager的模拟。可以设置您的模拟对象,以便对ProcessWorkItem的调用只需立即调用操作,并允许私有方法保持私有。可能会将您的业务逻辑注入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来验证您的业务逻辑。我看不出在声明这些内部方法时存在任何问题。将整个OrderService实现放在一个单独的库中,并从主应用程序中引用它。主应用程序只能使用公共部分。顺便问一下,你如何让你的开发人员不把这种方法从私有改为公有?你为什么要写这些东西?这不是一个解决了的问题吗?你想达到什么目标?
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;
}
}
}
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);
}
}
}