我的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创建对象,因为它们具有内部构造函数。
如何在单元测试中隔离这些类。或者我应该从单元测试中排除服务上下文部分。
答案 0 :(得分:1)
我会创建一个从服务结构返回参数的接口(其中一个是连接字符串)。然后是一个按照你在问题中写的方式实现接口的类。并且可以模拟在单元测试中使用该接口。 结果是 - 您无法测试实际从服务参数读取的方法,但至少您可以测试使用它的每个人,而无需模拟ServiceContext等。
答案 1 :(得分:1)
现在您可以使用名为ServiceFabric.Mocks的NuGet包,它为大多数Service Fabric类提供模拟。
例如,您可以使用MockStatelessServiceContextFactory.Default来获取StatelessServiceContext模拟。
答案 2 :(得分:0)
我与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属性,但你可以把它扩展到你喜欢的东西(显然)。