【问题标题】:Isolating Service Fabric ServiceContext for unit testing隔离 Service Fabric ServiceContext 以进行单元测试
【发布时间】:2016-09-14 19:20:16
【问题描述】:

我的 Service Fabric 无状态服务应用程序中有一个方法,它从 ServiceContext 获取存储在 Settings.xml 中的配置

public static string GetConnectionString()
{
    if (context == null)
        return string.Empty;

    // return context.CodePackageActivationContext.GetConfigurationPackageObject("Config").Settings.Sections["MySection"].Parameters["ConnectionString"].Value;

    ICodePackageActivationContext activationContext = context.CodePackageActivationContext;
    ConfigurationPackage configPackage = activationContext.GetConfigurationPackageObject("Config");
    ConfigurationSettings configSettings = configPackage.Settings;
    string connectionString = configSettings.Sections["ConnectionData"].Parameters["ConnectionString"].Value;
    return connectionString;
}    

在上面的代码中,我将代码分成多行以便于理解,实际上我在我的应用程序中使用了注释代码。

我需要为此方法编写单元测试。 我可以模拟 ServiceContext 和 ICodeActivationContext

但我无法为 ConfigurationSettings 和 ConfigurationPackage 创建对象,因为它们具有内部构造函数。

如何在单元测试中隔离这些类。或者我应该从我的单元测试中排除服务上下文部分。

【问题讨论】:

    标签: c# unit-testing azure-service-fabric isolation


    【解决方案1】:

    现在您可以使用名为 ServiceFabric.Mocks 的 NuGet 包,它为大多数 Service Fabric 类提供模拟。

    例如,您可以使用 MockStatelessServiceContextFactory.Default 来获取 StatelessServiceContext 模拟。

    【讨论】:

    【解决方案2】:

    我将创建一个从服务结构返回参数的接口(其中之一是连接字符串)。然后是一个按照您在问题中编写的方式实现接口的类。并且可以在单元测试中模拟该接口。 结果是 - 您无法测试实际从服务参数读取的方法,但至少您可以测试使用它的每个人,而无需模拟 ServiceContext 等。

    【讨论】:

    • 这就是我最后所做的,我们与 microsoft SME 家伙打了个电话,他说,在当前版本中,我们无法模拟 ServiceContext,因为它是一个非常复杂的对象。推荐的方式就像你在上面的评论中提到的那样。谢谢!
    【解决方案3】:

    我对 System.Printing PrintSystemJobInfo 类有一个几乎相同的问题,它有一个密封的构造函数,因此证明它很难模拟。我假设您正在创建一个与您希望模拟的类非常相似的接口,然后为实现该接口的实际类创建一个包装器。

    解决您的问题的方法是将父类作为参数传递给子类的构造函数(这样子类就可以访问父方法,并且可以构建您打算包装的真实实现)。

    下面的代码演示了我是如何使用 PrintSystemJobInfo 的;

    using System;
    using System.Printing;
    
    namespace ConsoleApplication6
    {
    class Program
    {
        static void Main(string[] args)
        {
            var server = new LocalPrintServer();
    
            IPrintQueue testablePrintQueue = new RealPrintQueue(server);
    
            IPrintSystemJobInfo  printSystemJobInfo = testablePrintQueue.AddJob();
    
            var result = printSystemJobInfo.IsBlocked;
    
            Console.WriteLine(result);
    
        }
    
        public interface IPrintSystemJobInfo
        {
             bool IsBlocked { get; }
        }
    
        public interface IPrintQueue
        {
            IPrintSystemJobInfo AddJob();
        }
        public class RealPrintQueue:IPrintQueue
        {
            private PrintQueue _queue; 
            public RealPrintQueue(LocalPrintServer server)
            {
                _queue = server.DefaultPrintQueue;
            }
    
            public IPrintSystemJobInfo AddJob()
            {
                return new RealPrintSystemJobInfo(_queue);
            }
    
        }
    
        public class RealPrintSystemJobInfo: IPrintSystemJobInfo
        {
            private PrintSystemJobInfo job;
            public RealPrintSystemJobInfo(PrintQueue queue)
            {
                job = queue.AddJob();
            }
    
            public bool IsBlocked
            {
                get { return job.IsBlocked; }
            }
        }
    }
    

    }

    我尽量保持简单,所以我只包装了 IsBlocked 属性,但你可以将它扩展到你喜欢的任何东西(显然)。

    【讨论】:

    • 附注如果我的答案不起作用(对不起,我试过了),请考虑更改问题的标题(我不知道您是否真的可以),我认为您当前的标题不能很好地描述您非常有效的问题。例如,如何使用密封的构造函数来模拟一个类的层次结构......
    猜你喜欢
    • 1970-01-01
    • 2017-09-02
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多