How we can perform integration test on service fabric (stateless service)? - c#

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.

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.

There is no difference on your integration tests on stateless web api with a regular api.

Related

Why use AddScoped() instead of AddSingleton()?

Why I should use AddScoped() for my repositories or services? Why not AddSingleton()?
I know about differences between them, but dont understand why I shouldn't use singleton instances to avoid creating new objects for each requests.
Can you explain it (preferably with examples :) )?
As you said, you know the difference so I won't get into that.
The reason you don't want addSingleton for your repositories or services is because typically your repositories and services are considered "business logic" and "persistence logic". And in your business logic you might have some class level variables that are getting set. Those properties would not be different for every request, they would be shared across the requests. (think of them like static properties).
Example:
Imagine you have a user service that sets the username of the user making the request as a class level variable.
Singleton logic:
Now imagine Bob makes a request to the api. The username would be set to "Bob" . Now imagine at the same time, John makes a request to the api. The username would get set to "John". But because the user service is a singleton, both John and Bob are sharing the same instance, meaning Bob's username would also be set to "John".
Scoped logic:
Imagine the exact same scenario as above, but this time when John makes a request, it does not override bobs username, because they are different instances.
The below three methods define the lifetime of the services,
AddTransient
Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.
AddScoped
Scoped lifetime services are created once per request.
AddSingleton
Singleton lifetime services are created the first time they are requested (or when ConfigureServices is run if you specify an instance there) and then every subsequent request will use the same instance.
Reference here
Imagine you have a aspnet-core project.
If you want to create an object only once during the program's runtime and use the same object each time, you should use addingingleton.
If you want an object to be new() again every time it receives a request while the program is running, you should use addscoped().
If you want an object to new() every request and response, you must use AddTransient.
Example value of 3 methods
Understanding with an infographic

Where is the instance of a WCF object stored?

I'm going to be creating a service that needs to make a call to a hosted WCF service halfway around the world. This isn't that big of a deal since the number of transactions that will be made is relatively low. However, I need to pass in an instance of a class that will possibly be defined in the WCF to the necessary WCF function.
So my question is, will that instance of the class exist on my server? Or will I be contacting the host server every time I attempt to set a variable in the object?
EXAMPLE:`
public class Dog
{
public string noise;
public int numLegs;
}
public class doSomething
{
public string makeNoise(Dog x)
{
return x.noise;
}
}
`
All of those are defined in the WCF. So when I create an instance of class Dog locally, will that instance exist on my side or the server hosting the WCF service? If I'm setting 1000 instances of Dog, the latency will definitely build up. Whereas if I DON'T have to contact the server every time I make a change to my instance of Dog, then the only time I have to worry about latency is when I pass it into doSomething.makeNoise.
The host creates a new instance of the service class for each request, if you're using the default per-call instantiation method (which is the recommended way).
So either this is the IIS server which hosting your WCF service that creates an instance of your service class, or it is the ServiceHost instance that you've created inside your own self-hosting setup (a console app, a Windows service etc.).
The service class instance is used to handle your request - execute the appropriate method on the service class, send back any results - and then it's disposed again.
There's also the per-session mode in which case (assuming the binding you've chosen support sessions) your first call will create a service-class instance, and then your subsequent calls will go to the same, already created instance (until timeouts come into play etc.).
And there's also the singleton mode, where you have a single instance of the service class that handles all requests - this is however rather tricky to get right in terms of programming, and "challenged" in terms of scalability and performance
You will need to host your WCF service on a public available server (for example IIS). Successful hosting will provide you with a link for the svc file. Clicking on that will give you a link ending in singleWsdl. You need to copy that link. On your client side, the one that requires a reference to the WCF, you will need to Add Service Reference and pass that link. This will generate proxy code with Client objects that you can use to access your WCF ServiceOperation methods.
At a minimum you should have three projects. A website project to host the actual site. A WCF project to host your services. And finally a shared project, which should contain the classes you are concerned with (the models).
Both the website and wcf projects should reference the shared project, this way they both know how the models look.
The wcf project should return serialzed models as json objects, which I usually do by referencing Newtonsoft.Json.
Your website project should expect this json, and deserialize them, also using Newtonsoft.Json. This is why your class (model) should exist in the shared project, so you can use the same class on both sides of your service call.

Injecting SMTPclient into a behavior, how to test?

I'm setting up an application and I'm injecting a bunch of behaviors into a service using Unity. There is a constructor, something like:
public class WhateverService(IBehavior[] behaviors) : IService {}
All of this is set up like while setting up the container, something like:
container.RegisterType<IBehavior, LogBehavior>("LogBehavior");
container.RegisterType<IBehavior, SomeOtherBehavior>("SomeOtherBehavior");
container.RegisterType<IService, WhateverService>();
Injection is done in the WCF service project, obviously.
Now I want to add a MailNotificationBehavior. So there's a bunch of SMTP settings that need to save somewhere. Since this SMTP config is a deployment thing, I want to use deafault web.config SMTP settings configurations.
The web.config is in the same project where the container configuration is being done, so the MailNotificationBehavior needs to be either injected with all of these settings, OR, just an instance of SmtpClient.
Something like:
container.RegisterType<IBehavior, MailNotificationBehavior>("MailNotificationBehavior", new new InjectionConstructor(new SmtpClient()));
Problem with this is - how will I be able to test this later on?
Should I write an interface ISmtpClient with an adapter for the actual SMTPClient, so I can fake it, or is this bad design to begin with?
Why are you relying on injection in your automated tests? You could/should write a unit test which instantiates the service and setups the service with mock "behaviours".
Reasoning: Your unit test should isolate the lines you want to test. Using injection makes your unit test also about testing if the injection works and if the right behaviour is available in the context of your service. You don't want either if you write a test for the service.
About the design; altough design by interface is nice, it's overdesign if you never plan on switching concrete smtp libraries. Another thing that kinda smells is creating "Behaviour". Your service does something (has effect on it's surroundings etc), that's it's behaviour. The behaviour of your service is calling a method on the implementations of IBehaviour and thereby changing the application state.
What you actually want to do is use AOP to add logging / email behaviour to your application by implementing them as aspects.

How can I host multiple IoC-driven WCF services in MVC?

I have around 6 WCF services that I want to host in an MVC application, routing requests to /services/foo to WcfFooService and /services/bar to WcfBarService
I can accomplish IoC with StructureMap within the services and inject my constructor dependencies by using the example that Jimmy Bogard blogged about here:
Jimmy's article is great, but I'm trying to extend it to work with multiple services hosted within the same MVC application. Essentially, the part at the bottom is the part that is causing me a few headaches:
public class StructureMapServiceHostFactory : ServiceHostFactory
{
public StructureMapServiceHostFactory()
{
ObjectFactory.Initialize(x => x.AddRegistry<FooRegistry>());
//var iTriedThisToo = ObjectFactory.Container;
//container.Configure(x => x.[etc]);
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new StructureMapServiceHost(serviceType, baseAddresses);
}
}
With a single WCF service - routing MVC requests to a specific url via the StructureMapServiceHostFactory shown above works brilliantly - but - If (for example) I create a StructureMapServiceHostFactory2 for the /services/bar call, to allow for a different Registry to be used, when the MVC app spins up, it appears to call each factory in turn as it runs through RouteConfig.cs and adds the routes, so ultimately I don't get configured instances that the first ServiceHostFactory should provide.
It doesn't make a difference if I call Initialize(); or attempt to grab the Container property and call Configure on it, either.
Am I on a hiding to nothing with this? The major reason for requiring registry isolation is due to different NHibernate configuration, but I could configure Named instances of SessionFactory and Session for NHibernate purposes and then use a single registry to get around this. In my mind I wanted the WCF service and MVC-hosting to be capable of using their own IoC containers in isolation, which is why I went down this route.
Is there any way that I can accomplish this?
Ok, so it would appear the only person capable of answering this was me, by virtue of a re-think and 're-architecting' the solution so that the problem doesn't exist in the first place.
I now have a capable way of hosting these services and maintaining IoC with StructureMap neatly per service, without any conflicting concerns.
If you find yourself in a similar position with SOA taking over (SOATO?) - taking a step back is a good start ;)

pass Business Layer to WCF service

I have a WCF service and i am trying to write unit test cases for that. I am calling Business Layer and some other WCF service from one of the methods in that service. I am already using IcO pattern for my Business Layer. but in order to use Mock object of my Business Layer and WCF service here, i need to pass it at the time of creating that service instance. If i change my default constructor to accept it as a parameter, i will have to expose them to the service consumers.
if i change the constructor of the service, it will look like this:
public MyService(MyBusinessLayer bl, SomeWCFService otherSrvc)
{
}
Is it OK to do so? Am i doing something wrong here?
Send an interface of the service instead of an impementation. That way you can swap out the implementation at runtime with your mock.

Categories

Resources