首页 文章

C# - 如何在 生产环境 者/消费者场景中对私有方法进行单元测试? [重复]

提问于
浏览
-1

这个问题在这里已有答案:

我想弄清楚是否有一些好的做法如何在 生产环境 者/消费者场景中对业务逻辑进行单元测试?

我们在应用程序中使用的设计是几个公共方法接受来自外部系统的请求,将它们放在一个“任务队列”中,然后有另一个线程负责处理队列中的任务 . 问题是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;
        }
    }
}

4 回答

  • 0

    也许将您的业务逻辑注入 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 验证您的业务逻辑 .

  • 1

    如果您不想更改当前实现,请使用模拟框架(如Moq),并创建 taskManager 的模拟 . 您可以设置模拟对象,以便对 ProcessWorkItem 的调用立即调用操作并允许私有方法保持私有 .

  • 0

    我将它们更改为内部并移动到独立库 . 之后我会做一个可以看到内部的TestClass,并在那里实现一些代理调用这些方法的公共“methodsExtensionsTesting”,并在你的unitTests中调用它们,这样你就可以直接检查它们 .

  • 1

    您应该根据给定的参数测试该私有方法将更改的状态 .

    如果使用外部资源(数据库,文件系统,其他API:s)的私有方法,您应该抽象它们并作为依赖项传递给类,在单元测试中,您可以模拟它们并针对模拟依赖项声明逻辑 .

    另一种方法是遵循"Single Responsibility principle" . 有了这个原则,类只应该有一个改变的理由 .
    此刻我看到了下一个原因

    • 当您更改业务逻辑以处理收到的订单时,您需要更改您的类 .

    • 当您更改处理不同订单的方式时(在队列或集合中或以其他方式),您需要更改类 .

    因此,您可以将订单处理移到类外部,并将其作为依赖项传递给队列类 .

相关问题