I'ld like to perform integration on stateless service in service fabric.Please help me on this. I have created the stateless service like c# web api.
2 Answers
In order to perform integration tests on your Reliable Service there is a number of dependencies you need to mock and take care of. You will not be able to test all situations or behavior of your service this way, the way the FabricRuntime
hosts and runs services is difficult to replicate (without writing your own FabricRuntime equivalency). It is also worth noting that there is no way to run FabricRuntime
without a cluster (including local development cluster).
You also need to consider how advanced your integration tests should be. For instance, does your service call out to other service (including actors) within the same cluster using fabric transport (the default communication model) that you want to include in your integration test? Do you need to ensure that state is persisted across multiple activations of the same service partition?
First you need to get rid of all hard dependencies to FabricRuntime
(to things with dependencies to it) and also static support classes in your code:
Service/Actor proxy
Don't use the static ServiceProxy.Create<..)(..)>
when calling other services, instead make sure your Service accepts an instance of IServiceProxyFactory
in the constructor and use that instance to create proxies to services your service calls. Same goes for ActorProxy.Create<..>(..)
, replace this with an instance of IActorProxyFactory
. In your program.cs
where the service is constructed, give the service new ServiceProxyFactory()
and new ActorProxyFactory()
. That's the easy part, now you need to mock those so that your integration tests can actually create some form of proxy for downstream services. You will also need to create some form of container (like a mock FabricRuntime) that holds instances of called services and actors. It also gets tricky if you wan't to test that the RunAsync
method of your service performs some function. Beware of creating this static though if you want to run it in a test runner,
you don't want different tests to get mixed up in the same container.
Service context
You need to mock your StatefulServiceContext
well and how your Service is created. Your Service constructors need to accept an instance of StatefulServiceContext
to pass along to the base class, so you are free to supply your own mocked instances of context there when you create the service.
public StatefulService(StatefulServiceContext serviceContext)
: base(serviceContext) {}
Service settings and activation context
You also need to see if your service implementation tries to read ICodePackageActivationContext
or any of the settings from the Service manifest (like shown in this SO answer Where do you set and access run-time configuration parameters per environment for service fabric?). In that case you need to replace it with your own mockable version and you need to inject that in the constructor as well. What you find in most samples is a call to the service context, like this:
this.Context.CodePackageActivationContext.GetConfigurationPackageObject("Config");
If you do it this way in your service then you need make sure you have a mock of StatefulServiceContext
as well and how your Service is created. When you register your service with the runtime in Program.Main()
then you get and instance of StatefulServiceContext
in the register call:
ServiceRuntime.RegisterServiceAsync("ServiceType",
context => new Service(context)).GetAwaiter().GetResult();
State
In order to mock state and get it to behave similar to what it will when running in a real cluster you need to mock the underlying handler for reliable state: IReliableStateManagerReplica
and you need to add an overloaded constructor to your services that accepts an instance of that and sends it to the base:
public StatefulService(StatefulServiceContext serviceContext, IReliableStateManagerReplica reliableStateManagerReplica)
: base(serviceContext, reliableStateManagerReplica) {}
For actors its IActorStateProvider
you need to mock if you want to handle state in your integration tests.
Summary
Depending on how advanced you want your integration tests to be and how close to the real execution model you want it to be, you may end up having to mock and replace a large number of classes/interfaces. The Web reference application sample https://github.com/Azure-Samples/service-fabric-dotnet-web-reference-app has some implementation of Mocks for required classes, also https://github.com/loekd/ServiceFabric.Mocks contains Mocks for testing, although you might need to alter the code if you really want to run integration tests and not just unit tests.

- 352
- 1
- 7
- 24

- 3,285
- 1
- 14
- 27
There is no difference on your integration tests on stateless web api with a regular api.

- 6,787
- 10
- 46
- 87
-
If your stateless web api communcates with other services in the cluster using fabric transport or tries to read the config for the service (e.g. a connectionstring) using the CodePackageActivationContext then your integration tests will fail unless you allow for some form of mocking of those dependencies or you are actually running your integration tests on a real cluster. – yoape Jan 23 '17 at 19:37
-
1I think this is for integration test. So nothing should be mock. – alltej Jan 23 '17 at 20:17
-
1In that case your only option is to run the test on a real cluster and in which case your testing would involve automating deployment to a cluster, populating some known data state and driving som form of interaction with the services. Yes, in that case it is possible to run it that way, but likely requiring a lot of work. You could in that case use the [``FabricClient.TestManagementClient``](https://learn.microsoft.com/en-us/dotnet/api/system.fabric.fabricclient.testmanagementclient) to setup the desired data state. – yoape Jan 23 '17 at 20:22
-
I think the answer to the question whether you should mock or stub anything in an integration test depends on who you are asking. The version where you don't mock anything is in my mind usually a Factory integration test or a Site integration test. There might a be a scenario where you are _not_ testing the entire system but you are still interested in testing more connected components or parts than in a unit test. I think a lot of people refer to that _bigger-than-a-unit-test_, perhaps sloppily, as integration test... jm2c – yoape Jan 23 '17 at 20:32