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.
This type of testing follows the natural control flow hierarchy, i.e., top to bottom. For example, you have a fitness app with four modules – A login page, a profile page, a workout page, and a payment page. The testing of the application will start from the crucial top-level module.
Integration testing tools are used to test the interface between modules and find the bugs; these bugs may happen because of the multiple modules integration. The main objective of these tools is to make sure that the specific modules are working as per the client's needs.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With