unit testing - Unittest SignalR Hubs
unit-testing nunit (6)
Con SignalR 2.0 puedes hacerlo de esta manera:
// Arrange
var hub = new CodeInteractivePreviewHub();
var mockClients = new Mock<IHubCallerConnectionContext<dynamic>>();
hub.Clients = mockClients.Object;
dynamic all = new ExpandoObject();
mockClients.Setup(m => m.All).Returns((ExpandoObject)all);
// Act
var allSourceCodes = hub.InitiateCommunication(); //Change this line to your Hub''s method
// Assert
Assert.IsNotNull(allSourceCodes);
Me gustaría probar mi Hub en SignalR, ¿cuál es el mejor enfoque?
Posibles soluciones que he pensado hasta ahora:
- Crear un centro comprobable
- Lógica abstracta para separar la clase
- Selenio (quisiera probar unidades más pequeñas)
- ¿O se han pasado por alto algunas características de prueba de SignalR?
Actualmente usa SignalR 0.4 y NUnit como marco de prueba.
Es muy fácil de crear para probar los concentradores SignalR utilizando un par de trucos ingeniosos. Una cosa a tener en cuenta es que SignalR usa clases dynamic
que pueden no ser compatibles con su marco de burla (yo uso NSubstitute ).
public class ProjectsHub: Hub
{
public void AddProject(string id)
{
Clients.All.AddProject(id);
}
}
[TestFixture]
public class ProjectsHubTests
{
// Operations that clients might receive
// This interface is in place in order to mock the
// dynamic object used in SignalR
public interface ISignals
{
void AddProject(string id);
}
[Test]
public void AddProject_Broadcasts()
{
// Arrange
ProjectsHub hub = new ProjectsHub();
IHubCallerConnectionContext clients =
Substitute.For<IHubCallerConnectionContext>();
ISignals signals = Substitute.For<ISignals>();
SubstituteExtensions.Returns(clients.All, signals);
hub.Clients = clients;
// Act
hub.AddProject("id");
// Assert
signals.Received(1).AddProject("id");
}
}
Reescribir esto para usar, por ejemplo, Moq debería ser bastante simple.
Esta es una versión modificada de la respuesta de Iarsm, para trabajar con XUnit y MOQ.
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Moq;
using Xunit;
namespace TestLibrary {
public class ProjectsHub : Hub {
public void AddProject(string id) {
Clients.All.AddProject(id);
}
}
public class ProjectsHubTests {
// Operations that clients might receive
// This interface is in place in order to mock the
// dynamic object used in SignalR
public interface ISignals {
void AddProject(string id);
}
[Fact]
public void AddProject_Broadcasts() {
// Arrange
ProjectsHub hub = new ProjectsHub();
var clients = new Mock<IHubCallerConnectionContext<dynamic>>();
var signals = new Mock<ISignals>();
hub.Clients = clients.Object;
signals.Setup(m => m.AddProject(It.Is<string>(s => s == "id"))).Verifiable();
clients.Setup(m => m.All).Returns(signals.Object);
// Act
hub.AddProject("id");
// Assert
signals.VerifyAll();
}
}
}
Esta pregunta es de hace un tiempo, pero haré todo lo posible para responder de todos modos.
Si tiene mucha lógica en su clase central actual, sin duda tendría sentido resumir la lógica en una clase separada. Hice lo mismo con mi demo multiplayer alimentada por SignalR. El único comportamiento que debe ir en su clase de concentrador es el relacionado con la mensajería. Todas las acciones adicionales deben ser delegadas.
Nota: Esto es muy similar a las pautas para el diseño del controlador en ASP .NET MVC: Mantenga sus controladores pequeños y delegue el trabajo real.
Si quiere pruebas de integración con SignalR que realmente hace algo de trabajo, selenium webdriver sería una buena opción. Pero probablemente necesite hacer algunos ajustes para que la mensajería SignalR funcione perfectamente en el contexto de las pruebas. Haga una búsqueda en google de "signalr selenium" (sin las comillas) para comenzar en el camino correcto.
Algunos blogs sobre pruebas automatizadas para SignalR => aquí y aquí
Este enlace muestra cómo probar los métodos del concentrador SignalR usando Moq. Usted simula el repositorio, los clientes, el contexto y la persona que llama. Aquí está el código del sitio, hice algunos cambios menores para que funcione con el último SignalR:
public class TestableChatHub : ChatHub
{
public Mock<IChatRepository> MockChatRepository { get; private set; }
public TestableChatHub(Mock<IChatRepository> mockChatRepository)
: base(mockChatRepository.Object)
{
const string connectionId = "1234";
const string hubName = "Chat";
var mockConnection = new Mock<IConnection>();
var mockUser = new Mock<IPrincipal>();
var mockCookies = new Mock<IRequestCookieCollection>();
var mockRequest = new Mock<IRequest>();
mockRequest.Setup(r => r.User).Returns(mockUser.Object);
mockRequest.Setup(r => r.Cookies).Returns(mockCookies.Object);
Clients = new ClientProxy(mockConnection.Object, hubName);
Context = new HubCallerContext(mockRequest.Object, connectionId);
var trackingDictionary = new TrackingDictionary();
Caller = new StatefulSignalProxy(
mockConnection.Object, connectionId, hubName, trackingDictionary);
}
}
Luego, el sitio muestra que puede usar este concentrador comprobable para escribir pruebas unitarias:
[TestClass]
public class ChatHubTests
{
private TestableChatHub _hub;
public void SetUpTests()
{
_hub = GetTestableChatHub();
}
[Test]
public void ExampleTest()
{
SetUpTests();
const string message = "test";
const string connectionId = "1234";
var result = _hub.Send(message);
_hub.MockChatRepository.Verify(r => r.SaveMessage(message, connectionId));
Assert.IsTrue(result);
}
private TestableChatHub GetTestableChatHub()
{
var mockRepository = new Mock<IChatRepository>();
mockRepository.Setup(m => m.SaveMessage(
It.IsAny<string>(), It.IsAny<string())).Returns(true);
return new TestableChatHub(mockRepository);
}
}
Personalmente creo que la mejor manera es la que se da: http://www.asp.net/signalr/overview/testing-and-debugging/unit-testing-signalr-applications