How do I set up Moq so that I can unit test adding multiple groups and clients in SignalR? - signalr

I've been working on coming with a SignalR Unit testing framework using Moq.
I have been able things to get reasonably well with the 1 group - 1 client (connection) scenario.
How do I set up Moq so I can:
1) Add/remove multiple clients from the same group?
2) Add/remove multiple groups on the same mocked hub?
I'm relatively new to the world of Moq and SignalR combination.
Thanks in advance,
JohnB

Here is an example testing adding a client to multipe groups using Moq and xUnit.net:
[Fact]
public async Task MyHubAddsConnectionToTheCorrectGroups()
{
// Arrange
var groupManagerMock = new Mock<IGroupManager>();
var connectionId = Guid.NewGuid().ToString();
var groupsJoined = new List<string>();
groupManagerMock.Setup(g => g.Add(connectionId, It.IsAny<string>()))
.Returns(Task.FromResult<object>(null))
.Callback<string, string>((cid, groupToJoin) =>
groupsJoined.Add(groupToJoin));
var myHub = new MyHub();
myHub.Groups = groupManagerMock.Object;
myHub.Context = new HubCallerContext(request: null,
connectionId: connectionId);
// Act
await myHub.AddToGroups();
// Assert
groupManagerMock.VerifyAll();
Assert.Equal(3, groupsJoined.Count);
Assert.Contains("group1", groupsJoined);
Assert.Contains("group2", groupsJoined);
Assert.Contains("group3", groupsJoined);
}
public class MyHub : Hub
{
public async Task AddToGroups()
{
await Groups.Add(Context.ConnectionId, "group1");
await Groups.Add(Context.ConnectionId, "group2");
await Groups.Add(Context.ConnectionId, "group3");
}
}
The basic idea is to define a Callback along with your Setup that stores arguments important to your test inside a collection. You can then use the collection verify that the method you mocked was called the right number of times with the right arguments. I don't verify the order of the calls to Groups.Add in my example test, but you can test that as well.
This pattern extends pretty trivially to testing the adding/removing of multiple clients. Basically, you would just need a second collection to store the connectionId arguments passed to Groups.Add.

Related

Consuming Asp.Net Core api locally

I don't know if my google skills are diminishing or what but I can't seem to figure out how to consume a local api. This may be best explained with sample code...
So I have a simple api
public class FooApiController : Controller
{
public IActionResult GetFoo(int id)
{
if (id == 0)
return BadRequest();
var data = ... do db access
return Ok(data);
}
}
and a view controller
public class FooController : Controller
{
public IActionResult Foo()
{
var api = new FooApiController();
var data = api.GetFoo(1);
ViewBag.Data = data;
return View();
}
}
So in the above view controller I call the api to get the data needed. However, being that the api controller returns an IActionResult, ViewBad.Data ends up being an IActionResult object. So how do I change the above to check the StatusCode of the api call, handle errors if need be, and if not... put just the data into the ViewBag, instead of the entire result object.
Every sample I have found seems to have the view controller return a view that then uses an ajax call to get the data. While I understand and could easily do that, I don't like the idea of making 2 round trips to the server when I don't need to.
You are doing it wrong.
If you want to reuse the code among multiple controllers, then it is better to move it from the GetFoo method and put it into a shared class and access it from everywhere else.
If you want to call it from a view through REST, then call it using $.ajax
ex:
$.ajax('FooApi/GetFoo/5',function(data){alert(data);});
If you want to access it from another C# client, then use the HttpClient class, ex:
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync("api/FooApi/GetFoo", 3);
response.EnsureSuccessStatusCode();

Some questions concerning the combination of ADO.NET, Dapper QueryAsync and Glimpse.ADO

I have been experimenting with a lightweight solution for handling my business logic. It consists of a vanilla ADO.NET connection that is extended with Dapper, and monitored by Glimpse.ADO. The use case for this setup will be a web application that has to process a handful of queries asynchronously per request. Below a simple implementation of my setup in an MVC controller.
public class CatsAndDogsController : Controller
{
public async Task<ActionResult> Index()
{
var fetchCatsTask = FetchCats(42);
var fetchDogsTask = FetchDogs(true);
await Task.WhenAll(fetchCatsTask, fetchDogsTask);
ViewBag.Cats = fetchCatsTask.Result;
ViewBag.Dogs = fetchDogsTask.Result;
return View();
}
public async Task<IEnumerable<Cat>> FetchCats(int breedId)
{
IEnumerable<Cat> result = null;
using (var connection = CreateAdoConnection())
{
await connection.OpenAsync();
result = await connection.QueryAsync<Cat>("SELECT * FROM Cat WHERE BreedId = #bid;", new { bid = breedId });
connection.Close();
}
return result;
}
public async Task<IEnumerable<Dog>> FetchDogs(bool isMale)
{
IEnumerable<Dog> result = null;
using (var connection = CreateAdoConnection())
{
await connection.OpenAsync();
result = await connection.QueryAsync<Dog>("SELECT * FROM Dog WHERE IsMale = #im;", new { im = isMale });
connection.Close();
}
return result;
}
public System.Data.Common.DbConnection CreateAdoConnection()
{
var sqlClientProviderFactory = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SqlClient");
var dbConnection = sqlClientProviderFactory.CreateConnection();
dbConnection.ConnectionString = "SomeConnectionStringToAwesomeData";
return dbConnection;
}
}
I have some questions concerning the creation of the connection in the CreateAdoConnection() method. I assume the following is happening behind the scenes.
The call to sqlClientProviderFactory.CreateConnection() returns an instance of System.Data.SqlClient.SqlConnection passed as a System.Data.Common.DbConnection. At this point Glimpse.ADO.AlternateType.GlimpseDbProviderFactory kicks in and wraps this connection in an instance of Glimpse.Ado.AlternateType.GlimpseDbConnection, which is also passed as a System.Data.Common.DbConnection. Finally, this connection is indirectly extended by the Dapper library with its query methods, among them the QueryAsync<>() method used to fetch the cats and dogs.
The questions:
Is the above assumption correct?
If I use Dapper's async methods with this connection - or create a System.Data.Common.DbCommand with this connection's CreateCommand() method, and use it's async methods - will those calls internally always end up using the vanilla async implementations of these methods as Microsoft has written them for System.Data.SqlClient.SqlConnection and System.Data.SqlClient.SqlCommand? And not some other implementations of these methods that are actually blocking?
How much perf do I lose with this setup compared to just returning a new System.Data.SqlClient.SqlConnection directly? (So, without the Glimpse.ADO wrapper)
Any suggestions on improving this setup?
Yes pretty much. GlimpseDbProviderFactory wraps/decorates/proxies all the registered factories. We then pass any calls we get through to the factory we wrap (in this case SQL Server). In the case of CreateConnection() we ask the inner factory we have, to create a connection, when we get that connection, we wrap it and then return it to the originating caller
Yes. Glimpse doesn't turn what was an async request into a blocking request. We persevere the async chain all the way though. If you are interested, the code in question is here.
Very little. In essence, using a decorator pattern like this adds only one or two frames to the call stack. Compared to most operations performed during the request lifecycle, the time to observe whats happening here is extremely minimal.
What you have looks great. Only suggestion is to maybe us this code to build the factory. This code means that you can shift your connection string, etc to the web.config.

How to set user host address in request

I found this code for doing a mock request for the purposes of unit testing. I'm trying to set the userhostaddress but I'm not clear how to use the same method outlined in this code to achieve that. I'm thinking it has to be done through reflection as I'm finding setting the headers is not allowed. Any ideas how I can achieve this?
public static HttpContext FakeHttpContext()
{
var httpRequest = new HttpRequest("", "http://fakurl/", "");
var stringWriter = new StringWriter();
var httpResponse = new HttpResponse(stringWriter);
var httpContext = new HttpContext(httpRequest, httpResponse);
var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
new HttpStaticObjectsCollection(), 10, true,
HttpCookieMode.AutoDetect,
SessionStateMode.InProc, false);
httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance,
null, CallingConventions.Standard,
new[] { typeof(HttpSessionStateContainer) },
null)
.Invoke(new object[] { sessionContainer });
httpContext.Request.Headers["REMOTE_ADDR"] = "XXX.XXX.XXX.XXX"; // not allowed
return httpContext;
}
I also tried this mocking library:
https://gist.github.com/rally25rs/1578697
By the user host address is still readonly.
Best approach I've found is to have some sort of ContextService that implements an IContextService interface. This class/interface pair can do whatever operations you need it to. Point is, if you use a mocking framework in your unit tests like MOQ then you can wire up a mock context service to return a particular ip address.
This StackOverflow post has some good pointers: Moq: unit testing a method relying on HttpContext.
UPDATE:
The StackOverflow post you found is also a good one: How to set the IP (UserHostAddress) on a "mocked' BaseHttpContext?
I find that often I'll only need a few properties off of the context/request/response objects, so I often roll my own smaller variant:
public class ContextService : IContextService
{
public string GetUserHostAddress()
{
return HttpContext.Current.Request.UserHostAddress;
}
}
public interface IContextService
{
string GetUserHostAddress();
}
With that class/interface combo, I can then use Moq to wire up a fake service:
var contextMock = new Moq.Mock<IContextService>();
contextMock.Setup(c => c.GetUserHostAddress()).Returns("127.0.0.1");
Now every time I call contextMock.GetUserHostAddress(), I'll get "127.0.0.1". Rolling your own can be a great learning experience, especially if you don't need all the bells and whistles of a full-blown (or as full as possible anyway) HttpContext mock.

Unit testing with WebAPI odata

I am trying to move from a WebAPI based REST service, to one encompassing the new implimentation of OData. I have the service working correctly, but am at a loss on how create unit tests that will test the odata query options.
when unit testing WebAPI methods, I am used to building the httpRequestMessage and injecting it in the constructure:
var request = new HttpRequestMessage();
request.Headers.Add("UserName", "TestUser");
request.Headers.Add("Password", password);
request.Headers.Add("OverRideToken", "false");
request.Headers.Add("AccessSystem", "Mobile");
request.Headers.Add("Seed", "testSeed");
var token = new Token();
var authController = new AuthorizationController(request);
try
{
var returnValue = authController.Get();
how would I go about injecting the odata request? I need to verify that $filter, $inlinecount, and other options are returning the proper records.
You can either test your controller or you can test against a running instance of your Web API (you should probably do both).
Testing your controller won't achieve what you are trying to do, so you will want to test by creating a self hosted in-memory instance of your Web API application. You can then either use HttpClient in your test classes (you will have to manually construct OData requests), or you can use the WCF Data Services Client in your test classes (this will allow you to query via LINQ).
Here's an example using WCF Data Services Client:
public class ODataContainerFactory
{
static HttpSelfHostServer server;
public static MyApplicationServer.Acceptance.ODataService.Container Create(Uri baseAddress)
{
var config = new HttpSelfHostConfiguration(baseAddress);
// Remove self host requirement to run with Adminprivileges
config.HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.Exact;
// Register Web API and OData Configuration
WebApiConfig.Register(config);
// Configure IoC
ConfigureIoC(dataSource, config);
// Do whatever else, e.g. setup fake data sources etc.
...
// Start server
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
// Create container
var container = new MyApplicationServer.Acceptance.ODataService.Container(new Uri(baseAddress.ToString() + "odata/"));
// Configure container
container.IgnoreResourceNotFoundException = true;
container.IgnoreMissingProperties = true;
return container;
}
private static void ConfigureIoC(MockDatasource dataSource, HttpSelfHostConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<TypeA, TypeB>();
...
...
config.DependencyResolver = new IoCContainer(container);
}
public static void Destroy()
{
server.CloseAsync().Wait();
server.Dispose();
}
}
The key here is the WebApiConfig.Register(HttpConfiguration config) method call, which is calling your Web API project.
Note that prior to the above you will need:
Fire up your Web API project
In your test class add a Service Reference to your OData root path.
This will create a Container object (in the example above MyApplicationServer.Acceptance.ODataService.Container), which you can use to query your OData feed in your tests as follows:
var odataContainer = ODataContainerFactory.Create(new Uri("http://localhost:19194/");
var result = odataContainer.MyEntities
.Expand(s => s.ChildReferenceType)
.Where(s => s.EntityKey == someValue).SingleOrDefault();

What are the things that you test in a controller?

Let say you have a register action in your controller.
[HttpPost]
public ViewResult Register(string username, string email, string password, string repeatPassword)
This action will:
Check and validate parameters
Communicate and add a new data to
repository
Return a View.
Definitely need to unit test 1 and 3, but how about 2?
Is there any way to unit test 2 without having to implement the add method in the repository?
Thanks,
RWendi
Your test for #2 using Moq would be:
[Test]
public void UserIsAddedToRepository()
{
// arrange
var username = "user1";
var email = "email#address";
var password = "password";
var controller = new LoginController();
var mockUserRepo = new Mock<IUserRepo>();
mockUserRepo.Setup(m => m.AddNewUser(username, email, password));
// act
controller.Register(username, email, password, "");
// assert
mockUserRepo.Verify(m => m.AddNewUser(username, email, password));
}
Moq's Verify will behave like NUnit Assert and will fail the test if the expected method is not called.
In order to test number 2, you can use mocking. You can mock your repository and return valid result for the test.
You can do the mock manually (in several ways, for example pass a parameter to the action method with the relevant repository - real or mock; or instantiate the controller class with the relevant mock object etc.) or you can use a mocking library like Moq.

Resources