如何使用 ServiceFabric.Mocks Nuget 包模拟配置和数据包的 CodePackageActivationContext

Posted

技术标签:

【中文标题】如何使用 ServiceFabric.Mocks Nuget 包模拟配置和数据包的 CodePackageActivationContext【英文标题】:How do you Mock CodePackageActivationContext for Config and Data Package using ServiceFabric.Mocks Nuget package 【发布时间】:2021-03-28 16:12:34 【问题描述】:

这是Specific questions about unit-testing Service Fabric Applications using Mocks的后续问题

我正在使用 Xunit 和 ServiceFabric.Mocks 对我的应用程序进行单元测试。 我的 Service Fabric 应用程序如下所示:

namespace SearchService

    internal sealed class SearchServiceClass : StatelessService
    
        //variables defined followed by constructor
        private string jsonStr;
        public SearchServiceClass(StatelessServiceContext context)
            : base(context)
        
            try
            
                var section = Context.CodePackageActivationContext
                .GetConfigurationPackageObject("Config")
                .Settings
                .Sections[_configSectionName];
                var _parameters = section.Parameters.ToDictionary(kv => kv.Name, kv => kv.Value);
                //_parameters used to set further variables in the constructor
                var dataPackage = Context.CodePackageActivationContext
                .GetDataPackageObject("Data");
                jsonStr = File.ReadAllText(dataPackage.Path + @"\data.json");
                //removed code for brevity
            
            catch
            
                //exception handling code
                throw;
            
        
        
        public bool IsDataJsonLoaded
        
            get
            
                return !(jsonStr == null);
            
        
    

初始单元测试如下所示:

using Xunit;
using ServiceFabric.Mocks;

namespace App.UnitTests

    public class SearchServiceTest
    
        [Fact]
        public void SearchServiceClassConstructor()
        
            var searchServiceClass = new SearchServiceClass(MockStatelessServiceContextFactory.Default);
            //assert:
            Assert.True(searchServiceClass.IsDataJsonLoaded);
        
    

当我运行此单元测试时,“System.NullReferenceException:对象引用未设置为对象的实例。”抛出异常。这是因为在单元测试设置中,“Context.CodePackageActivationContext.GetDataPackageObject("Data");"将 null 返回到“dataPackage”。因此 IsDataJsonLoaded 上的断言返回 'False'。

我在 *** 上四处搜索,发现这个答案最能回答我的问题:https://***.com/a/57803921/14761454 但是在使用这个答案中的代码时,我的单元测试看起来像这样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServiceFabric.Mocks;
using SearchService;
using Xunit;
using static ServiceFabric.Mocks.MockConfigurationPackage;

namespace App.UnitTests

    public class SearchServiceTest
    
        [Fact]
        public void SearchServiceClassConstructor()
        
            //Arrange
            const string path = "../SearchService/PackageRoot/Data"; //The Data Package lives in the SearchService project, specifically PackageRoot/Data
            const string name = "Data";
            const string version = "1.0.0";
            const string serviceManifestName = "SearchServicePkg";
            const string serviceManifestVersion = "1.0.0";
            var dataPackageDescription = MockDataPackage.CreateDataPackageDescription(name, version, serviceManifestName, serviceManifestVersion, path);
            var dataPackage = MockDataPackage.CreateDataPackage(path, dataPackageDescription);

            //build ConfigurationSectionCollection
            var configSections = new ConfigurationSectionCollection();
            //Build ConfigurationSettings
            var configSettings = CreateConfigurationSettings(configSections);
            //add one ConfigurationSection
            ConfigurationSection configSection = CreateConfigurationSection("SearchServiceConfigSection");
            configSections.Add(configSection);

            //add one Parameters entry
            ConfigurationProperty parameter = CreateConfigurationSectionParameters(nameof(parameter.Name), nameof(parameter.Value));
            configSection.Parameters.Add(parameter);
            var Context = MockCodePackageActivationContext.Default;

            var searchServiceClass = new SearchServiceClass(MockStatelessServiceContextFactory.Default);
            //Act
            Context.SetDataPackage(dataPackage);
            //Assert:
            Assert.True(searchServiceClass.IsDataJsonLoaded);
        
        
    

但是现在编译器会抛出错误,说在命名空间中找不到“ConfigurationSection”和“ConfigurationProperty”。

我在正确的轨道上吗?如果我这样继续,我是否完全能够从单元测试环境中的实际 StatelessService 模拟配置和数据包。如何先修复这些错误?

编辑:根据下面 LoekD 的响应,我已更新到 ServiceFabric.Mocks v4.2.8,并实现了附加代码来模拟数据包。但是 NullReferenceException 仍然存在。此错误对应于 SearchServiceClass 的构造函数中的“dataPackage.Path”行。虽然现在有一个单独的“MockCodePackageActivationContext.Default;”上下文和一个单独的“MockStatelessServiceContextFactory.Default”上下文在单元测试中传递给 SearchServiceClass 的构造函数,在 Mock StatelessServiceContext 中不存在 CodePackageActivation。不确定这是否有意义......但本质上,这似乎导致了构造函数中 dataPackage.Path 引用中的“NullReferenceException”。任何想法如何解决这个问题?

【问题讨论】:

尝试使用:csharpdoc.hotexamples.com/class/Iot.Mocks/… 【参考方案1】:

你在正确的轨道上!

第 1 步。

ConfigurationSectionConfigurationProperty 类位于 SF 命名空间 System.Fabric.Description 中。为命名空间添加using

第 2 步。

请升级到 ServiceFabric.Mocks v4.2.8。这增加了对模拟MockCodePackageActivationContext 上的DataPackage 属性的支持。 示例见this page。

第 3 步。

使用创建的上下文作为构造函数参数。 更改此代码:

var searchServiceClass = new SearchServiceClass(MockStatelessServiceContextFactory.Default);
            

进入这个:

var activationContext = new MockCodePackageActivationContext(
                "fabric:/MockApp",
                "MockAppType",
                "Code",
                "1.0.0.0",
                Guid.NewGuid().ToString(),
                @"C:\logDirectory",
                @"C:\tempDirectory",
                @"C:\workDirectory",
                "ServiceManifestName",
                "1.0.0.0")
            
                ConfigurationPackage = configPackage
            ;
activationContext.SetDataPackage(dataPackage);

var newUri = new Uri("fabric:/MockApp/SearchService");
var serviceTypeName = "SearchServiceType";
var partitionId = Guid.NewGuid();
var replicaId = long.MaxValue;

var serviceContext = MockStatelessServiceContextFactory.Create(activationContext, serviceTypeName, newUri, partitionId, replicaId);
var searchServiceClass = new SearchServiceClass(serviceContext);

【讨论】:

非常感谢。我首先修复了命名空间问题。然后我看到了模拟“DataPackage”的代码,在我的单元测试中实现了相同的。我没有得到的是如何修复我在运行单元测试时得到的“NullReferenceException”。此错误对应于 SearchServiceClass 的构造函数中的“dataPackage.Path”行。虽然现在有一个单独的“MockCodePackageActivationContext.Default;”在单元测试中将上下文和单独的“MockStatelessServiceContextFactory.Default”上下文传递给 SearchServiceClass 的构造函数,CodePackageActivation 不存在.. ..(续)在 Mock StatelessServiceContext 中。不确定这是否有意义......但本质上,这似乎导致了构造函数中 dataPackage.Path 引用中的“NullReferenceException”。任何想法如何解决这个问题? 我已经更新了我的问题。您能否看一下,让我知道我试图在构造函数中模拟的代码是否真的可以被模拟? 代替Default 实例,使用您自己定制的Context 实例作为构造函数参数(见上文)。 对不起,我混淆了服务上下文和代码包激活上下文,更改了我的代码。

以上是关于如何使用 ServiceFabric.Mocks Nuget 包模拟配置和数据包的 CodePackageActivationContext的主要内容,如果未能解决你的问题,请参考以下文章

如果加入条件,我该如何解决。如果使用字符串连接,我如何使用

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?