【问题标题】:How to stub and test protected members in a service?如何存根和测试服务中的受保护成员?
【发布时间】:2013-09-11 09:40:16
【问题描述】:

预故事:我正在测试一项服务。每隔 n 秒,它就会启动一些进程并运行一些作业。 我想通过集成测试覆盖此服务的顶层(从 ServiceBase 继承的类)。我的目标是验证:1. 我可以启动它,2. 它设置所有计时器,以及 3. 创建作业管理对象来执行作业(至少在计时器上看到一次执行)。 将来我们希望通过将不同的作业移动到不同的线程来提高性能,这也会增加代码的复杂性。(这是现在测试它的另一个原因,虽然它仍然很简单)

问题本身:我应该如何测试服务?此类中的所有方法和属性都是受保护的或私有的。而对于 RhinoMocks,我只能存根公共成员。

还有一些想法: 这个类中有一个私有成员 AppJobManagement,我想存根。我不想使用这个类的真实实例,因为它连接到数据库并且在运行时可能会做很多不需要的更改。 我可以将其公开以进行存根。

但我遇到的下一个问题是,我如何断言服务类可以正常工作?我将需要再次公开测试中的方法。这是我想避免的。

非常感谢任何建议!

【问题讨论】:

    标签: c# .net unit-testing service rhino-mocks


    【解决方案1】:

    您可以创建公共或内部构造函数来依赖AppJobManagement。如果可以,请更改对此类接口的引用,因为它可能会使测试更容易。

    public class ServiceToBeTested : ServiceBase
    {
        private IAppJobManagement _appJobManagment;
    
        public ServiceToBeTested()
        {
            _appJobManagment = new AppJobManagement();
        }
    
        internal ServiceToBeTested(IAppJobManagement appJobManagment)
        {
            _appJobManagment = appJobManagment;
        }
    }
    

    如果ServiceToBeTested 有许多您想模拟/伪造的受保护方法,您应该考虑另一个依赖项。例如,而不是:

    public void DoSomethingImportant(string foo)
    {
        if (someCondition)
        {
            DoThisOneWay(foo);
        }
        else
        {
            DoThisDifferently(foo);
        }
    }
    
    protected void DoThisOneWay(string foo) {}
    protected void DoThisDifferently(string foo) {}
    

    你可以使用另一个对象:

    public interface IServiceWorker
    {
        void DoThisOneWay(string foo);
        void DoThisDifferently(string foo);
    }
    
    public void DoSomethingImportant(string foo)
    {
        if (someCondition)
        {
            _worker.DoThisOneWay(foo);
        }
        else
        {
            _worker.DoThisDifferently(foo);
        }
    }
    

    IServiceWorker _worker 很容易被嘲笑。

    更新

    另一种模式是使用Factory 类来生成这些对象。

    public interface IAppJobManagementFactory
    {
        IAppJobManagement Create(string arg1, int arg2);
    }
    

    这也可以被嘲笑。

    【讨论】:

    • 感谢您的想法,但不幸的是我无法应用此解决方案,因为我在计时器经过事件中创建和销毁此对象。
    • @Anelook 为什么不能在测试方法中创建测试服务实例?在实际代码中如何实例化这个对象并不重要。
    猜你喜欢
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 2010-12-15
    • 2014-05-13
    • 2012-05-22
    • 2020-05-09
    相关资源
    最近更新 更多