Unit Testing on SignalR Hubs with 2.0 RC1

This is really only a bit of an extension upon what others have already put down in blogs but since info is scarse out there I think every bit helps.

Not only was the move from version SignalR 1.3 to 2.0 a bit of work to wrap your head around but now 2.0 does just about everything a bit differently. Given that your own research led you to "Upgrading SignalR 1.x Projects to 2.0" you and you have

  • removed "RouteTable.Routes.MapHubs();" from Application_Start(..)
  • and if you followed along an created the Startup.cs file put into the configuration your app.MapSignalR();

you now want your cross domain support back and you want your fricking backplane to work..  More digging and finally you come across another note with you Startup.cs Configuration(..)  looking more like this

public void Configuration(IAppBuilder app) {
 app.Map("/signalr", map => {
  var hubConfiguration = new HubConfiguration {
   //EnableJSONP = true
  //ServiceBusScaleoutConfiguration sbConfig = new ServiceBusScaleoutConfiguration(
  //WebConfigurationManager.AppSettings["Microsoft.ServiceBus.ConnectionString"], "test");
 //app.MapSignalR(); // Not needed as the CORS app.Map(...) does this


So after all that you finally have it working again with the latest 2.0 Release (Microsoft ASP.NET SignalR 2.0.0-rc1, etc) and you come to a point where you need to add unit tests for your SignalR work. Of course 2.0 RC1 came with a ton of other dependent packages and your packages config has not bloated to something like this with a mix of versions.  (Of course I believe the plan is that as of Oct 17th 2013 most of this will be out of RC1 and part of a larger MSFT update related to Azure for Windows Server relase plan)

  • Microsoft.AspNet.Cors
  • Microsoft.AspNet.SignalR
  • Microsoft.AspNet.SignalR.Core
  • Microsoft.AspNet.SignalR.JS
  • Microsoft.Owin
  • Microsoft.Owin.Cors
  • Microsoft.Owin.Host.SystemWeb
  • Microsoft.Owin.Security
  • Newtonsoft.Json
  • Owin

Now your thinking how the heck do I write a unit test around this monster.  Me too.. Other that looking over the git SignalR code and pulling it down and checking out their tons af version 1.3 Unit Tests I can't really find any help there for testing Hubs from the perspective of a Contextual Client.  The best I came across was a post on 3am Code called  "Unit Testing SignalR Hubs" but again it was kind of an older version they were testing against.

Well long story short Moq seems to be the test tool of choice so here goes nothing (and It's not much so comments from others to help this along are most welcome)

  1. For VS.Net 2012 create a new Unit Test Project to the same solution where your SignalR IIS project is at
  2. Grab and add to that project the "Microsoft ASP.NET SignalR Core Components 2.0.0-rc1" nuget package
  3. Grab Moq - I used this in my Unit Test project
    1. Install-Package Moq
  4. Within your Unit Test code file follow the advice from 3am Code site and add a class that inherits from your own Hub class
    1. Within the ctor of the new class you will need to add some code to be able to test your Hub Class methods
  5. While this by no means coverage from the perspective of testing Security, SSL if you are doing it that way or passing data structures to and from SignalR it's a small start. 
  6. My only intent was to test a single Method on my Hub to make sure the invoker was working and that data was passing though.  Not to test that broadcast was working or anything like that.  I'm sure you could use the 2.0 SignalR client code to test that capability if you want to extend to yet another test case.  Actually I'll have to add that to my own code I suppose but not to do a self hosted instance but against my own local running instance of SingalR.  (TODO)

My test inherited class looked like this and as you can see the ctor puts together some contextual data so the hub method invoke calls will actually work.

    public class TestableSignalRHub : MyChatHub {

        public IConfigurationManager _config;

        public TestableSignalRHub() : base()
            const string connectionId = "1234";
            const string hubName = "ChatHub";
            var resolver = new DefaultDependencyResolver();
            _config = resolver.Resolve<IConfigurationManager>();
            var mockConnection = new Mock<IConnection>();
            var mockUser = new Mock<IPrincipal>();
            //var mockCookies = new Mock<IRequestCookieCollection>();
            var mockHubPipelineInvoker = new Mock<IHubPipelineInvoker>();
            //IHubPipelineInvoker _pipelineInvoker = resolver.Resolve<IHubPipelineInvoker>();

            var mockRequest = new Mock<IRequest>();
            mockRequest.Setup(r => r.User).Returns(mockUser.Object);
            //mockRequest.Setup(r => r.Cookies).Returns(mockCookies.Object);

            StateChangeTracker tracker = new StateChangeTracker();

            //Clients = new HubConnectionContext(_pipelineInvoker, mockConnection.Object, hubName, connectionId, tracker);
            Clients = new HubConnectionContext(mockHubPipelineInvoker.Object, mockConnection.Object, hubName, connectionId, tracker);
            Context = new HubCallerContext(mockRequest.Object, connectionId);
            var x = Clients.Caller;



 Honestly I cant tell you the difference between creating a Hub Pipeline Invoker the one way or trying to do it the other way.. Both ways seems to work or make not difference.  Since the git for SignalR only seems to have 1.3 up there (did I need to dig deeper to the 2.1 RC?) I can't tell 100%

In the final [TestMethod] you then just

  1. instance you overloaded Hub then grab a MethodInfo handle for the type
    1. TestableSignalRHub hub = new TestableSignalRHub();
  2. MethodInfo methodInfo = typeof(TestableSignalRHub).GetMethod("SendMessage");
  3. I gutted a helper method internal out of SignalR and placed it into my Test Class so I could look and call the internal method.  You can find it in the git repo but you have to download the SignalR source code then search for "internal class HubMethodDispatcher" and pull that code into your class. After that you just need to do this.
    1.  HubMethodDispatcher dispatcher = new HubMethodDispatcher(methodInfo);
  4. All you need after that is to execute it against the Hub instance.  My code variation left out the user name in the param list buy you can add that to the parameters below.
    1. var parameters = new object[] { new string("hello world") };

    2. object returnValue = dispatcher.Execute(hub, parameters);

  5. In my case I was returnValue is always null beacuse my code was broadcasting it to Clients.All. 

Final result was a passed test. Well at least it called all the way through. 

Final thoughts: My next step is going to be creating a client wrap to my running instance and run a test harness against that.  I think that wont be as difficult but working through the git code base for SignalR they have a top of Unit Tests to learn from.  Please do leave comments or links to other works around unit testing as it is always appreciated.

Para obtener información más completa sobre las optimizaciones del compilador, consulte nuestro Aviso de optimización.