服务结构单元测试和依赖注入
本文关键字:依赖 注入 单元测试 结构 服务 | 更新日期: 2023-09-27 18:21:58
我不能通过调用可靠服务/参与者的构造函数然后测试它的方法来测试它。var testService = new SomeService();
抛出一个NullReferenceException。那么,我可以对部署的服务做些什么。。
我知道部署的SF Reliable Services/Actors不是标准的.NET类,对部署的S/A进行单元测试可能是个奇怪的想法。
不管怎样,现在我正试着试一试。
例如。我刚刚部署了一个Service,而在测试中,我创建了一个Proxy对象,并将项目添加到Service的输入队列中。然后我需要断言输入队列计数=1。如果我刚刚部署了一个服务,并且没有其他Clients/Services/Actor使用它的输入队列,那么它就可以工作。但下一次这个测试会失败,这就是问题所在。我需要让服务停止与其他使用者操作,删除它的队列,然后测试它。为此,我可以创建一些TestMode属性和一些方法,如PropareoForTests/TestingCompleted,并在测试前后从测试客户端调用它们。
这样做是个坏主意吗。也许有一些单元测试SF的指导方针吗?谢谢
更新:
在研究Service Fabric Web参考应用程序示例时,我发现了以下TODO字符串:
/// TODO: Temporary property-injection for an IServiceProxyWrapper until constructor injection is available.
这是否意味着SF Services将改进其DI支持?演员呢?
实际上,您可以像测试.NET中的任何其他类一样测试Reliable Services和Actors!它们的特殊之处在于,它们使用特定的钩子进入底层平台,但除此之外,您可以正常实例化服务或actor类,并在其上调用方法
目前,Reliable Services更容易进行单元测试,因为平台的主要挂钩State Manager是一个可通过构造函数插入的接口。
例如,您的服务类可能如下所示:
编辑:更新为API正式发行版(2.0.135)
class MyService : StatefulService
{
public MyService (StatefulServiceContext context, IReliableStateManager stateManager)
:base (context, stateManager)
{
}
public void MyMethod()
{
// do stuff..
}
}
然后你可以这样测试你的服务类:
[TestMethod]
public TestMyMethod()
{
MockReliableStateManager stateManager = new MockReliableStateManager();
MyService target = new MyService(stateManager);
target.MyMethod();
// validate results and all that good stuff
}
我们有一个完整的实际服务的工作示例,其中有许多依赖项正在GitHub上进行单元测试:https://github.com/Azure-Samples/service-fabric-dotnet-management-party-cluster
这个例子也有IReliableStateManager和IReliableDictionary模拟,您可以将它们用作自己的单元测试的起点。
为了嘲笑Reliable Actors中的状态管理器,您可以这样做:
private readonly IActorStateManager _stateManager;
public MyActor(IActorStateManager stateManager = null)
{
_stateManager = stateManager ?? this.StateManager;
}
实际上,StateManager
此时尚未初始化。当OnActivateAsync
被调用时,我们可以得到它:
private IActorStateManager _stateManager;
// Unit tests can inject mock here.
public MyActor(IActorStateManager stateManager = null)
{
_stateManager = stateManager;
}
protected override async Task OnActivateAsync()
{
if (_stateManager == null)
{
_stateManager = StateManager;
}
}
只需确保在代码的其余部分始终使用_stateManager
,而不是this.StateManager
。