17

我不能通过调用它的构造函数然后测试它的方法来测试一个可靠的服务/演员。var testService = new SomeService();引发 NullReferenceException。那么我可以用已部署的服务做什么..

我知道部署的 SF Reliable Services/Actor 不是标准的 .NET 类,对部署的 S/A 进行单元测试可能是一个奇怪的想法。

无论如何,现在我正在尝试尝试一下。

例如。我刚刚部署了一个服务,而不是在测试中我创建了一个代理对象并将项目添加到服务的输入队列中。然后我需要断言输入队列计数 = 1。如果我刚刚部署了一个服务并且没有其他客户端/服务/参与者使用它的输入队列,它就可以工作。但是下次这个测试将失败,这就是问题所在。我需要让服务停止与其他消费者一起操作,放下它的队列,然后测试它。为此,我可以创建一些 TestMode 属性和一些方法,如 PropareoForTests/TestingCompleted 并在测试前后从测试客户端调用它们。

这样做是不是一个坏主意。也许有一些关于单元测试 SF 的指南?谢谢。

更新:

在调查Service Fabric Web 参考应用程序示例时,我发现了这个 TODO 字符串:

/// TODO: Temporary property-injection for an IServiceProxyWrapper until constructor injection is available.

这是否意味着顺丰服务将改进其对 DI 的支持?演员呢?

4

2 回答 2

19

实际上,您可以像在 .NET 中测试任何其他类一样测试 Reliable Services 和 Actors!它们的特殊之处仅在于它们在底层平台中使用了某些挂钩,但除此之外,您可以正常实例化您的服务或参与者类并在其上调用方法。

目前,Reliable Services 更容易进行单元测试,因为进入平台的主要挂钩状态管理器是一个可通过构造函数插入的接口。

例如,您的服务类可能如下所示:

编辑:更新了 GA 版本 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 模拟,您可以将其用作您自己的单元测试的起点。

于 2015-11-20T23:48:44.807 回答
4

要在 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.

于 2016-05-26T11:28:43.803 回答