I am using nUnit Test and Signalr with .net framework 4.5 and I get error like :
System.Net.Http.HttpRequestException : An error occurred while sending the request.
----> System.Net.WebException : Unable to connect to the remote server
----> System.Net.Sockets.SocketException : No connection could be made because the target machine actively refused it 127.0.0.1:6790
Actually I need to test when hub.GetCallControlData(); being called then it should be invoked SetServer method
code :
[HubName("SignalRHub")]
public class SignalRHub1 : Hub
{
public override Task OnConnected()
{
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
return base.OnDisconnected(stopCalled);
}
public void GetCallControlData()
{
Clients.Caller.SetServer("Server");
}
}
Test
[TestFixture]
public class SignalrHubTest1
{
public interface IClientContract
{
void SetServer(string s);
}
[Test]
public async Task MockSingalrHub()
{
var url = "http://localhost:6790";
var connectionId = Guid.NewGuid().ToString();
var mockRequest = new Mock<IRequest>();
var mockClients = new Mock<IHubCallerConnectionContext<dynamic>>();
var mockProxy = new Mock<IHubProxy>();
var _connection = new HubConnection(url);
var clientContract = new Mock<IClientContract>();
var mockHeaders = new Mock<INameValueCollection>();
mockHeaders.Setup(h => h["host"]).Returns(url);
mockRequest.Setup(r => r.Headers).Returns(mockHeaders.Object);
clientContract.Setup(_ => _.SetServer(It.IsAny<string>()));
mockClients.Setup(m => m.Caller).Returns(clientContract.Object);
var hub = new SignalRHub1()
{
Clients = mockClients.Object,
Context = new HubCallerContext(mockRequest.Object, connectionId)
};
var _hub = _connection.CreateHubProxy("SignalRHub");
mockProxy.Setup(x => x.Subscribe(It.IsAny<string>())).Returns(new Subscription());
_hub.On<string>("SetServer", x => SetServer(x));
await hub.OnConnected();
hub.GetCallControlData();
clientContract.VerifyAll();
await _connection.Start();
}
internal void SetServer(string s)
{
// throw new NotImplementedException();
}
}
Unit tests are meant to be isolated. There is no need to connect to an actual server in order to verify expected behavior.
Given the shown Hub,
[HubName("SignalRHub")]
public class SignalRHub1 : Hub {
public void GetCallControlData() {
Clients.Caller.SetServer("Server");
}
}
the following isolated unit test behaves as expected and verifies that the SetServer("Server") is invoked.
[TestClass]
public class SignalrHub1Tests {
public interface IClientContract {
void SetServer(string s);
}
[TestMethod]
public void GetCallControlData_Should_SetServer() {
//Arrange
var contract = new Mock<IClientContract>();
contract.Setup(_ => _.SetServer(It.IsAny<string>()));
var mockClients = new Mock<IHubCallerConnectionContext<dynamic>>();
mockClients.Setup(_ => _.Caller).Returns(contract.Object);
var hub = new SignalRHub1() {
Clients = mockClients.Object
};
//Act
hub.GetCallControlData();
//Assert
contract.Verify(_ => _.SetServer("Server"));
}
}
Related
I am trying to follow their tutorial for tests:
Link to Orleans test docs
But the configuration shown is pretty simplistic:
var builder = new TestClusterBuilder();
var cluster = builder.Build();
cluster.Deploy();
And does not show how to add SMSProvider.
Let's say that I have the following test:
[Fact]
public async Task SaysHelloCorrectly()
{
var hello = _cluster.GrainFactory.GetGrain<ISomeGrain>(Guid.NewGuid(), "<Some stream ID>", "Some.Class.Path");
var guid = Guid.NewGuid();
var streamProvider = _cluster.Client.GetStreamProvider("SMSProvider");
var photoStream = streamProvider.GetStream<string>(guid, "<Some stream ID>");
await photoStream.OnNextAsync("Hi");
Assert.Equal("Hello, World", "Hello, World");
}
Then I get an error in line:
var streamProvider = _cluster.Client.GetStreamProvider("SMSProvider");
Such as:
[xUnit.net 00:00:02.02] Tests.SaysHelloCorrectly [FAIL]
Failed Tests.FilterTests.SaysHelloCorrectly [8 ms]
Error Message:
System.Collections.Generic.KeyNotFoundException : SMSProvider
I think that configuring the ClusterFixture correctly would be part of the solution or maybe the way I am getting the StreamProvider in the unit test is not correct.
All of the code looks like the following:
ClusterCollection:
using System;
using Orleans.TestingHost;
using Xunit;
namespace Tests {
[CollectionDefinition(ClusterCollection.Name)]
public class ClusterCollection : ICollectionFixture<ClusterFixture>
{
public const string Name = "ClusterCollection";
}
}
ClusterFixture:
public class ClusterFixture : IDisposable
{
private sealed class Configurator : ISiloBuilderConfigurator
{
public void Configure(ISiloHostBuilder siloBuilder)
{
siloBuilder.AddSimpleMessageStreamProvider("SMSProvider");
siloBuilder.AddMemoryGrainStorage("PubSubStore");
}
}
public ClusterFixture()
{
var builder = new TestClusterBuilder();
builder.AddSiloBuilderConfigurator<Configurator>();
this.Cluster = builder.Build();
this.Cluster.Deploy();
}
public void Dispose()
{
this.Cluster.StopAllSilos();
}
public TestCluster Cluster { get; private set; }
}
SomeTests:
[Collection(ClusterCollection.Name)]
public class SomeTests
{
private readonly TestCluster _cluster;
public SomeTests(ClusterFixture fixture)
{
_cluster = fixture.Cluster;
}
[Fact]
public async Task SaysHelloCorrectly()
{
var hello = _cluster.GrainFactory.GetGrain<ISomeGrain>(Guid.NewGuid(), "<Some stream ID>", "Some.Class.Path");
var guid = Guid.NewGuid();
var streamProvider = _cluster.Client.GetStreamProvider("SMSProvider");
var photoStream = streamProvider.GetStream<string>(guid, "<Some stream ID>");
await photoStream.OnNextAsync("Hi");
Assert.Equal("Hello, World", "Hello, World");
}
}
The setup needs to be improved. You can check this sample from the official Orleans GitHub page: https://github.com/dotnet/orleans/blob/main/test/TesterInternal/StreamingTests/SMSStreamingTests.cs
So, in your ClusterFixture class you should add the SiloConfigurator:
private class SiloConfigurator : ISiloConfigurator
{
public void Configure(ISiloBuilder hostBuilder) =>
hostBuilder.AddSimpleMessageStreamProvider("SMSProvider")
.AddMemoryGrainStorage("PubSubStore");
}
and the ClientConfiguretor:
private class ClientConfiguretor : IClientBuilderConfigurator
{
public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) =>
clientBuilder.AddSimpleMessageStreamProvider("SMSProvider");
}
And then in your ClusterFixture constructor:
public ClusterFixture()
{
var builder = new TestClusterBuilder();
builder.AddSiloBuilderConfigurator<SiloConfigurator>();
builder.AddClientBuilderConfigurator<ClientConfiguretor>();
this.Cluster = builder.Build();
this.Cluster.Deploy();
}
I'm using ASP.NET 6 Core and writing a basic integration test for a controller that uses a mocked DBContext. Trying to base it on the Microsoft docs. But I can't build because I'm getting
CS0051 Inconsistent accessibility: parameter type 'CustomWebApplicationFactory<Program>' is less accessible than method 'ProjectsControllerTests.ProjectsControllerTests(CustomWebApplicationFactory<Program>)' DatabaseManagerService
But they are both public?!
ProjectControllersTests.cs
public class ProjectsControllerTests
{
private readonly CustomWebApplicationFactory<Program> _factory;
private const string s_apiBaseUri = "/api/v1";
public ProjectsControllerTests(CustomWebApplicationFactory<Program> factory)
{
// Arrange
_factory = factory;
}
[Fact]
public async Task Post_Responds201IfAuthenticatedAndRequiredFields_SuccessAsync()
{
// Arrange
HttpClient? client = _factory.CreateClient(new WebApplicationFactoryClientOptions()
{
AllowAutoRedirect = false
});
var project = new Project() { Name = "Test Project" };
var httpContent = new StringContent(JsonSerializer.Serialize(project));
// Act
var response = await client.PostAsync($"{s_apiBaseUri}/projects", httpContent);
// Assert
Assert.Equal(System.Net.HttpStatusCode.Created, response.StatusCode);
}
}
CustomWebApplicationFactory.cs
public class CustomWebApplicationFactory<TStartup>
: WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var descriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<myDbContext>));
if (descriptor != null)
services.Remove(descriptor);
services.AddDbContext<myDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
});
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, MockAuthHandler>(
"Test", options => { });
var sp = services.BuildServiceProvider();
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<myDbContext>();
var logger = scopedServices
.GetRequiredService<ILogger<CustomWebApplicationFactory<Program>>>();
db.Database.EnsureCreated();
try
{
db.EndUsers.Add(new DataAccessLibrary.Models.EndUser() { ObjectIdentifier = "test-oid" });
db.SaveChanges();
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred seeding the " +
"database with test messages. Error: {Message}", ex.Message);
}
}
});
}
}
The Program class is not public in ASP.NET 6 Core. As per https://learn.microsoft.com/en-us/aspnet/core/migration/50-to-60-samples?view=aspnetcore-6.0#twa you can make Program public by appending the following to Program.cs:
public partial class Program { }
It should also be noted that the above test class must be defined as:
public class ProjectsControllerTests : IClassFixture<CustomWebApplicationFactory<Program>>
for DI to work.
I'm stuck and the docks for the lib are unhelpful. Given the below saga definition:
public class GetOrdersStateMachine : MassTransitStateMachine<GetOrdersState>
{
public State? FetchingOrdersAndItems { get; private set; }
public Event<GetOrders>? GetOrdersIntegrationEventReceived { get; private set; }
public GetOrdersStateMachine()
{
Initially(
When(GetOrdersIntegrationEventReceived)
.Activity(AddAccountIdToState)
.TransitionTo(FetchingOrdersAndItems));
}
private EventActivityBinder<GetOrdersState, GetOrders> AddAccountIdToState(
IStateMachineActivitySelector<GetOrdersState, GetOrders> sel) =>
sel.OfType<AddAccountIdToStateActivity>();
}
And the below activity definition:
public class AddAccountIdToStateActivity : Activity<GetOrdersState, GetOrders>
{
private readonly IPartnerService _partnerService;
public AddAccountIdToStateActivity(IPartnerService partnerService) => _partnerService = partnerService;
public void Probe(ProbeContext context) =>
context.CreateScope($"GetOrders{nameof(AddAccountIdToStateActivity)}");
public void Accept(StateMachineVisitor visitor) => visitor.Visit(this);
public async Task Execute(
BehaviorContext<GetOrdersState, GetOrders> context,
Behavior<GetOrdersState, GetOrders> next)
{
context.Instance.AccountId = await _partnerService.GetAccountId(context.Data.PartnerId);
await next.Execute(context);
}
public Task Faulted<TException>(
BehaviorExceptionContext<GetOrdersState, GetOrders, TException> context,
Behavior<GetOrdersState, GetOrders> next) where TException : Exception =>
next.Faulted(context);
}
And the below test definition:
var machine = new GetOrdersStateMachine();
var harness = new InMemoryTestHarness();
var sagaHarness = harness.StateMachineSaga<GetOrdersState, GetOrdersStateMachine>(machine);
var #event = new GetOrders("1", new[] {MarketplaceCode.De}, DateTime.UtcNow);
await harness.Start();
try
{
await harness.Bus.Publish(#event);
await harness.Bus.Publish<ListOrdersErrorResponseReceived>(new
{
#event.CorrelationId,
AmazonError = "test"
});
var errorMessages = sagaHarness.Consumed.Select<ListOrdersErrorResponseReceived>().ToList();
var sagaResult = harness.Published.Select<AmazonOrdersReceived>().ToList();
var state = sagaHarness.Sagas.Contains(#event.CorrelationId);
harness.Consumed.Select<GetOrders>().Any().Should().BeTrue();
sagaHarness.Consumed.Select<GetOrders>().Any().Should().BeTrue();
harness.Consumed.Select<ListOrdersErrorResponseReceived>().Any().Should().BeTrue();
errorMessages.Any().Should().BeTrue();
sagaResult.First().Context.Message.IsFaulted.Should().BeTrue();
errorMessages.First().Context.Message.CorrelationId.Should().Be(#event.CorrelationId);
errorMessages.First().Context.Message.AmazonError.Should().Be("test");
state.IsFaulted.Should().BeTrue();
}
finally
{
await harness.Stop();
}
As you can see, the AddAccountToStateActivity has a dependency on the IPartnerService. I can't figure a way to configure that dependency.There's nothing in the docs and neither can I find anything on the github. How do I do it?
Thanks to the help of one of the library's authors I ended up writing this code:
private static (InMemoryTestHarness harness, IStateMachineSagaTestHarness<GetOrdersState, GetOrdersStateMachine> sagaHarness) ConfigureAndGetHarnesses()
{
var provider = new ServiceCollection()
.AddMassTransitInMemoryTestHarness(cfg =>
{
cfg.AddSagaStateMachine<GetOrdersStateMachine, GetOrdersState>().InMemoryRepository();
cfg.AddSagaStateMachineTestHarness<GetOrdersStateMachine, GetOrdersState>();
})
.AddLogging()
.AddSingleton(Mock.Of<IPartnerService>())
.AddSingleton(Mock.Of<IStorage>())
.BuildServiceProvider(true);
var harness = provider.GetRequiredService<InMemoryTestHarness>();
var sagaHarness = provider
.GetRequiredService<IStateMachineSagaTestHarness<GetOrdersState, GetOrdersStateMachine>>();
return (harness, sagaHarness);
}
As you can see I'm registering my mocks with the ServiceProvider.
I'm trying to write an Unit Test for my ASP.Net Core application with XUnit framework and MOQ and am trying to test the below method(snippet given below):
public async Task<IActionResult> Save([FromBody] DTO.ContactUs contactUs)
{
contactUs.FirstName = _htmlEncoder.Encode(contactUs.FirstName);
contactUs.LastName = _htmlEncoder.Encode(contactUs.LastName);
contactUs.EmailAddress = _htmlEncoder.Encode(contactUs.EmailAddress);
contactUs.Phone = _htmlEncoder.Encode(contactUs.Phone);
if (HttpContext.User.CurrentClient() != null)
contactUs.ClientId = HttpContext.User.CurrentClient().ClientId;
contactUs.UserId = User.GetUserId();
string dbName = HttpContext.User.CurrentClient().ConnectionString;
var result = _clientService.AddNewContactUs(contactUs, dbName);
if (result)
{
try
{
int clientId = HttpContext.User.CurrentClient().ClientId;
var clientDetails = _clientService.GetClientDetailsByClientID(clientId);
// Lines of code...
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
return Json(result);
}
While I can mock all the other dependent services, I'm kind of stuck with the HttpContext part. I am not able to mock the HttpContext.User.CurrentClient() part where HttpContext.User is of type ClaimsPrincipal and CurrentClient is an user-defined function, defined as:
public static Client CurrentClient(this ClaimsPrincipal principal)
{
if (!string.IsNullOrEmpty(principal.Claims.Single(p => p.Type.Equals(AppClaimTypes.CurrentClient)).Value))
{
int clientId = Convert.ToInt32(principal.Claims.Single(p => p.Type.Equals(AppClaimTypes.CurrentClient)).Value);
return principal.GetClients().Where(c => c.ClientId == clientId).FirstOrDefault();
}
else
{
return null;
}
}
This is my UnitTest class that I have managed to write till now:
public class ContactUsControllerTests
{
private Mock<IClientService> clientServiceMock;
private Mock<IWebHostEnvironment> webHostEnvironmentMock;
private Mock<HtmlEncoder> htmlEncoderObjMock;
private Mock<IEmailNotification> emailNotificationMock;
private Mock<HttpContext> mockContext;
private Mock<HttpRequest> mockRequest;
private Mock<ClaimsPrincipal> mockClaimsPrincipal;
private ContactUs contactUsObj = new ContactUs()
{
FirstName = "TestFN",
LastName = "TestLN",
EmailAddress = "testemail#gmail.com",
Phone = "4564560000",
Comments = "This is just a test"
};
private ClaimsPrincipal principal = new ClaimsPrincipal();
public ContactUsControllerTests()
{
clientServiceMock = new Mock<IClientService>();
webHostEnvironmentMock = new Mock<IWebHostEnvironment>();
htmlEncoderObjMock = new Mock<HtmlEncoder>();
emailNotificationMock = new Mock<IEmailNotification>();
mockRequest = new Mock<HttpRequest>();
mockContext = new Mock<HttpContext>();
// set-up htmlEncoderMock
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.FirstName)).Returns(contactUsObj.FirstName);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.LastName)).Returns(contactUsObj.LastName);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.EmailAddress)).Returns(contactUsObj.EmailAddress);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.Phone)).Returns(contactUsObj.Phone);
htmlEncoderObjMock.Setup(h => h.Encode(contactUsObj.Comments)).Returns(contactUsObj.Comments);
// set-up mockContext
mockContext.Setup(m => m.Request).Returns(mockRequest.Object);
mockContext.Object.User.CurrentClient().ClientId = 30; // this throws error
//other initialisations
}
[Fact]
public async void SaveMethodTest()
{
ContactUsController contactUsControllerObj = new ContactUsController(clientServiceMock.Object, webHostEnvironmentMock.Object, htmlEncoderObjMock.Object, emailNotificationMock.Object);
// Act
await contactUsControllerObj.Save(contactUsObj);
// Arrange
// Lines of code
}
}
Any help whatsoever on this would very helpful.
I'm trying to mock SignalR broadcasting present in ApiController(WebApi), but unable to complete test case, below is my code
SignalRHub
public class HubServer : Hub { }
ApiControllerWithHub
public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub
{
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());
protected IHubContext Hub
{
get { return hub.Value; }
}
}
Controller (Method to Mock)
public class NotificationController : ApiControllerWithHubController<HubServer>
{
[HttpPost]
public HttpResponseMessage SendNotification(NotificationInput notification)
{
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
}
}
I'm writing following unit test with the help of Mock SignalR Post, I'm stuck here because this is SignalR call from controller not from SignalR Hub.
MockTest
public interface IClientContract
{
void BroadcastCustomerGreeting(string message);
}
[TestMethod]
public void SendNotificationTest()
{
NotificationInput notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";
// Arrange
var mockClients = new Mock<IHubConnectionContext<dynamic>>();
var mockGroups = new Mock<IClientContract>();
// Act.
mockGroups.Setup(_ => _.BroadcastCustomerGreeting("notification")).Verifiable();
mockClients.Setup(_ => _.Group("GroupName")).Returns(mockGroups.Object);
// I'm stuck here
var controller = new NotificationController();
// Act
HttpResponseMessage actionResult = controller.SendNotification(notificationInput);
}
Any help is appreciated to complete/correct this unit test.
Redesign needed. Base ApiController tightly coupled to static accessor of the hub context. This needs to be refactored out into its own service to allow for more flexibility via constructor injection.
public interface IHubContextProvider {
IHubContext Hub { get; }
}
public class HubContextProvider<THub> : IHubContextProvider where THub : IHub {
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());
public IHubContext Hub {
get { return hub.Value; }
}
}
Controllers now need to be refactored to explicitly expose its dependencies.
public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub {
private readonly IHubContext hub;
public ApiControllerWithHubController(IHubContextProvider context) {
this.hub = context.Hub;
}
protected IHubContext Hub {
get { return hub; }
}
}
public class NotificationController : ApiControllerWithHubController<HubServer> {
public NotificationController(IHubContextProvider context)
: base(context) {
}
[HttpPost]
public IHttpActionResult SendNotification(NotificationInput notification) {
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
return Ok();
}
}
Test can now be exercised with necessary mocks of dependencies.
[TestMethod]
public void _SendNotificationTest() {
// Arrange
var notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";
var groupName = "GroupName";
var message = "notification";
var mockGroups = new Mock<IClientContract>();
mockGroups.Setup(_ => _.BroadcastCustomerGreeting(message)).Verifiable();
var mockClients = new Mock<IHubConnectionContext<dynamic>>();
mockClients.Setup(_ => _.Group(groupName)).Returns(mockGroups.Object).Verifiable();
var mockHub = new Mock<IHubContext>();
mockHub.Setup(_ => _.Clients).Returns(mockClients.Object).Verifiable();
var mockHubProvider = new Mock<IHubContextProvider>();
mockHubProvider.Setup(_ => _.Hub).Returns(mockHub.Object);
var controller = new NotificationController(mockHubProvider.Object);
// Act
var actionResult = controller.SendNotification(notificationInput);
//Assert
mockClients.Verify();
mockGroups.Verify();
mockHub.Verify();
}
Just make sure to register new service with DI container so that it can be injected into dependent controllers.
With the redesign the base controller can be removed all together and the hub provider used directly. This is assuming that there was not any other reason to have the base controller.