How do I Unit Test NServiceBus.Configure.WithWeb()? - c#

I'm building a WCF service that receives requests on an external IP and translates them into messages that are sent via NServiceBus.
One of my unit tests invokes Global.Application_Start(), which performs the configuration of the application, and then attempts to resolve the web service to
validate that the container can build up all of the dependencies.
This works fine when I'm using Configure.With() in my windows services, but
the call to Configure.WithWeb() fails in this context (presumably because the "bin"
directory does not exist?).
Is it possible to unit test a method that calls Configure.WithWeb(), or should I
just use the overload for Configure.With() that takes a directory name?

I created a new startup class like so:
public class NonWebRunAtStartup : IRunAtStartup
{
public void InitializeInfrastructure(object container)
{
Configure.With()
.StructureMapBuilder((IContainer) container)
.Log4Net()
.XmlSerializer()
.MsmqTransport()
.UnicastBus()
.LoadMessageHandlers()
.CreateBus()
.Start();
}
}
Then in my test, I ensured that my IOC container would use this one instead of the usual web-based one by adding this to my test:
IoC.Register<IRunAtStartup, NonWebRunAtStartup>();
This got me to a different error, which I'm still fighting with, which I'll ask as a separate question (now NSB can't load assemblies that are in NServiceBus.Core.dll, such as Antlr3.Runtime.dll).

Related

How can I end to end test this .net core console application?

I have a .Net Core 2.0 console application. The main() method is like this:
public static async Task Main()
{
// create host builder
var hostBuilder = new HostBuilder();
var myApp = new MyApplication();
// Build host
var host = hostBuilder
.ConfigureHostConfiguration(myApp.ConfigureHostConfiguration)
.ConfigureServices(myApp.ConfigureServices)
.ConfigureLogging(myApp.ConfigureLogging)
.Build();
// Initialise
await myApp.InitialiseAppAsync(host);
// Run host
await host.RunAsync(CancellationToken.None);
}
The MyApplication class sets up the application configuration in ConfigureHostConfiguration(), it then configures up the dependencies in ConfigureServices() some of which register a Message Handlers to handle specific Messages types from an Azure Service Bus. The application needs to do some initialisation from within InitialiseAppAsync(). When host.RunAsync() is called, the a console application is run indefinitely and the Message Handler receives execution as soon as a message is available on the Azure Service Bus. This is all great and working fine.
What I'd like to do is create a new project under the same solution which contains some end to end tests (using XUnit). I'd like to be able to override some of the dependencies (with test mocks, using NSubstitute), leaving the other dependencies as they are configured in the service.
I'm guessing I'd need to create my own HostBuilder in my test, so I'll need to be able to setup the mocks before the host.RunAsync() call is made within the test.
Does anyone know how I can do this? Or what is the best practice for doing this?
Ultimately, what I'm trying to do is be able to override some (but not all) of my real dependencies in my Console Application with mocks, so I can do some end to end tests.
Thanks in advance
There are multiple ways to achieve this. You can set up the environment variable "environment" when you start up your application. Then you would need to run your application passing it like this:
dotnet "MyApplication.dll" --environment end2endTests
Then you will be able to find the value you passed as the environment at IHostEnvironment instance which is injectable. This is how your DI registrations would look like:
services.AddScoped<IFoo>(provider =>
{
var env = provider.GetRequiredService<IHostEnvironment>();
if (env.EnvironmentName == "end2endTests")
{
return new TestFoo();
}
return new RealFoo();
});

Windows Service - WCF Service Design

I have a Windows Service that hosts a WCF service and I am successfully able to connect to it using WCFTestClient and a Custom Client. The windows service is based upon what used to be an exe, but since the program will be used for a long running process on a server, the service is a better route. The problem is that I cannot access static variables in the application from the WCF service.
In the .exe (I switched this to a .dll which is the server application) I use a global class implemented as such:
public static class Globals
{
....
}
This holds references to the major parts of the program so that if any part needs to reference another I can use the syntax Globals.JobManager.RunJob().
The problem that I am encountering is that the WCF service is not able to reference Globals at run-time. One example of where I need this to be done is in the GetJob method:
public class ConsoleConnection : IConsoleConnection
{
public string[] RetrieveJobList()
{
string[] jobs = Globals.JobManager.GetAllJobNames().ToArray();
return jobs;
}
}
This method returns null when tested in WCFTestClient and throws an exception in the created client.
I believe this issue to be caused by the way the Windows Service, WCF Service, and the application DLL are initiated. The current method is such:
public class ETLWindowsService : ServiceBase
{
....
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
Globals.InitializeGlobals();
serviceHost = new ServiceHost(typeof(ConsoleConnection));
serviceHost.Open();
}
....
}
Here the Windows Service starts, Calls the Globals.InitializeGlobals() that creates all the necessary parts of the application, then starts the WCF service (If this is the wrong way to do this, let me know. I'm piecing this together as I go). I'm assuming that these actions are being done in the wrong order and that is the cause of the problems.
Do I need to have the Windows Service create the WCF Service which in turn creates the application (this doesnt make sense to me), or do I have the Windows Service create the application which then creates the WCF Service? Or is there a third option that I am missing?
The application is in a .dll with the WCF in a separate .dll
I totally agree with Andy H.
If I review this kind of code, I won't try to make the stuff work with the global static variable (even if in the end this is probably possible). A static global class is smelly. First of all, I will figure out to make it work without it.
There are several solution: dependency injection, messaging communication, event driven...
To help you: a long running process in a web service is very common, youy have a good description
here. But in any case, it never uses a static class to synchronize the jobs :)
Improve your design, and you will see that your current problem won't exist at all.

hosting webservice in unitTest

I want to host WCF service inside unit Test using ServiceHost.
And then running them in on a build machine.
Is it possible to host web services like this ? if yes how it's done ?
Thanks
Sure, you just use a ServiceHost like you would if it was a self-hosted wcf service. I typically do this in a test fixture/class setup/teardown.
For example with NUnit:
[TestFixture]
public class MyTests
{
private ServiceHost service;
[TestFixtureSetUp]
public void FixtureSetUp()
{
service = new ServiceHost(typeof(MyService));
service.Open();
}
[Test]
public void ThisIsATest()
{
using (var client = new MyServiceClient())
client.DoStuff(); // test whatever
}
[TestFixtureTearDown]
public void FixtureTearDown()
{
if (service != null)
{
if (service.State == CommunicationState.Opened)
service.Close();
else if (service.State == CommunicationState.Faulted)
service.Abort();
}
}
}
You will also need to copy any WCF XML configuration into the test assembly's app.config.
One thing to note however is the threading model of your unit test framework. If it is possible for your test runner to run multiple test classes simultaneously, then you might try to open the same service on the same port more than once, and it might fail.
On a final note, I would typically separate tests that do and don't fire up the actual WCF service. Put tests that don't hit WCF into a separate "Unit Tests" assembly, that runs without dependencies and runs fast, and put ones that do use WCF into an "Integration Tests" assembly instead. That is just a recommendation of course, not a rule.
It is indeed possible and actually is the same as hosting a WCf service in a console application!
Add your app.config to the UT assembly and proceed as always.
(You can also configure programatically of course).
Similarly, you create a client for the host in code.
Instantiate and open your host and client on the set-up method, you can do this per test or per class, depending on the level of isolation you seek.
So you see, you don't have to have a separate deployment stage.
Having said all the above, I would actually discourage you from working with services in your Unit tests. One of the best practices concerning unit tests is that they should be very fast to run. Making calls to web services (even local) is very costly in UT.
Moreover, this kind of contradicts the semantics of a UNIT test. You should be testing small bits of functionality. And strive to mock out external dependencies such as Database access, External services and even other classes. I would be happy to elaborate and refer to more information if you feel like it.
I think the problem here is that UnitTests are usually just a set of binaries that are executed by some other framework (NUnit, xUnit,...).
You can try on the TestSuite setup start another Thread and run WCF on that Thread, but I believe it is much more involved into this approach and Test suites may no like it as well.
What I would do is to setup a deployment step on your build machine of the WCF service to IIS or redeployment to the Windows Service hosted WCF before running UnitTests.

Dependency Injection and project structure for Console applications

I have 4 projects:
Core (IServer):
System
System.Core
DependencyResolver:
Core
StructureMap
Infrastructure (Service):
Core
External dependency
Console:
Core
DependencyResolver
Requierements:
I am trying to use StructureMap only in the DependencyResolver.
Furthermore the Console application should not know anything about Infrastucture.
When I do not want to reference StructureMap on my Console Application I have to build a ServiceLocator.
In the DependencyResolver I have a Bootstrapper that is responsible for calling StructureMap registry stuff (Register)
In my Console application I want to get an instance. For this I need to reference StructureMap. Another way would be to write a little wrapper around StructureMaps resolving methods.
Is there any other better way of decoupling the console from StructureMap?
While I see a reason for separating IoC register,resolve,release from the implementation of the application, I don't see any reason why the IoC container shouldn't be in the console application (the composition root) and the application implemention in another assembly instead.
That way the console application is very easy:
Create the container
Load the container configuration
Resolve the Application
Call run on the application and pass the console arguments along
dispose the container when the application exits the run method
With SM it look about like this:
public void Main(params string[] args)
{
using (var container = new Container())
{
container.LoadAllConfigurationModules();
container.AddRegistry<SomeRegistry>();
container.GetInstance<Application>().Run(args);
}
}
For things you can't create at startup you create a factory interface in your application assembly:
interface ISomeFactory { ISomeDependency CreateSomeDependency() }
and implement this interface in the console application by injecting the container and use it to resolve the instance. I guess the SM implementation looks like this:
public class SomeFactory : ISomeFactory
{
public SomeFactory(IContainer sontainer) { this.container = container; }
ISomeDependency CreateSomeDependency() { this.container.GetInstance<ISomeDependency>(); }
}
Other IoC container even have the functionallity to implement these interface factories automatically.

Restart a WCF service hosted by a C# console application

I have a WCF service that is hosted on a c# console application. Is there a way to restart this service, preferably by calling an endpoint in the service itself (ex. myService.Restart()).
Thanks
I have to do something similar when I perform an automatic update of a remote WCF service. In your Restart() method, close the host:
try
{
host.Description.Endpoints.Where(x => !x.Address.ToString().EndsWith("MEX")).ForEach(endpoint => _log.InfoFormat("Closing {0}", endpoint.Address));
host.Close(TimeSpan.FromSeconds(5));
}
catch (Exception)
{
host.Abort();
}
I wait for my update to apply, and then after a success or failure, I re-open the host using the same code I used to start it in the first place.
If you just wanted to restart immediately, you could just call host.Open(), or you could set up a timer to call it, etc.
try
{
host.Open();
host.Description.Endpoints.Where(x => !x.Address.ToString().EndsWith("MEX")).ForEach(endpoint => _log.InfoFormat("Host opened at: {0}", endpoint.Address));
}
catch (Exception ex)
{
_log.Error("Unable to open host.", ex);
}
To answer my question, I have solved the problem by doing the following:
Separating the code that loads the DLL files from the WCF service code into another class library project
Create an interface with the same method signatures as the ones that load DLL files in the new project (this interface is used by both projects now)
In the web service, load the other project in a new application domain. This way the DLL files are locked by the new application domain not the default.
If I want to update my nunit DLL files now, all I have to do is unload the application domain from the web service, update the files and finally create a new application domain.
AppDomain remoteDomain = AppDomain.CreateDomain("New Domain");
IClass1 class1 = (IClass1)remoteDomain.CreateInstanceFromAndUnwrap(
"Test1.dll", "Test1.Class1");
Note: IClass1 is the common interface between the projects.
you definitely are not going to be able to 'restart' a faulted service from calling that same service itself. In theory you could host 2 services in the same process. put the one you want to be 'restartable' in a public static variable and restart it within the other service. The problem would be restarting the restarter service if it faults... :) and you definitely want 'administrator-like' restrictions on your restarter service so unauthorized users can't do it.
It's a bit kludgy, but I suppose you could expose a callback on your service that the host could attach to and take appropriate action when it's triggered. That would give your host the ability to decide what a "restart" really means and how it needs to be executed. More importantly, it lets your decide whether it should do something extreme like spawn off a watcher process and then off itself or gracefully trash and reinstantiate your service (preferable).
Mmmmmm... kludge....
You cannot ask a service to restart itself. Consider a windows service (a service hosted in windows provided container) which has a RESTART functionality. Here RESTART functionality is provided not by the service but by the container. The container controls how to stop the service and start it.
Similarly in your case, you should try to look out for options if your container can provide the functionality you need. Since you want to control it remotely, the container should also be available remotely, which cannot be possible if the container is a console application. Instead it has to be another web service or web application.

Categories

Resources