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