我想在SignalR中测试我的Hub,最好的方法是什么?
到目前为止我已经考虑过可能的解决方案:
目前使用SignalR 0.4和NUnit作为测试框架。
答案 0 :(得分:8)
这个link展示了如何使用Moq对SignalR集线器方法进行单元测试。您模拟了存储库,客户端,上下文和调用者。这是网站上的代码,我做了一些小改动,使其适用于最新的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);
}
}
然后该站点显示您可以使用此可测试集线器来编写单元测试:
[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);
}
}
答案 1 :(得分:5)
使用一些巧妙的技巧创建单元测试SignalR集线器非常简单。需要注意的一点是SignalR使用了dynamic
类,你的模拟框架可能不支持这些类(我使用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");
}
}
重写此内容以便使用,例如Moq应该很简单。
答案 2 :(得分:4)
这个问题是从不久前开始的,但无论如何我都会尽力回答。
如果你的实际集线器类中有很多逻辑,那么将逻辑抽象到一个单独的类中肯定是有意义的。我为SignalR驱动的多人游戏演示做了同样的事情。您的集线器类本身应该进行的唯一行为是与消息传递相关的行为。应该委派所有进一步的行动。
注意:这与ASP .NET MVC中的控制器设计指南非常相似:保持控制器的小型化并委派实际工作。
如果你想让SignalR的集成测试真正做一些工作,那么selenium webdriver将是一个不错的选择。但是您可能需要进行一些调整以使SignalR消息在测试环境中完美地工作。谷歌搜索“signalr selenium”(没有引号)开始正确的轨道。
答案 3 :(得分:2)
使用SignalR 2.0,您可以这样做:
// 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);
答案 4 :(得分:0)
这是Iarsm答案的修改版本,可与XUnit和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();
}
}
}
答案 5 :(得分:0)
我个人认为最佳方式是给定的 - http://www.asp.net/signalr/overview/testing-and-debugging/unit-testing-signalr-applications
答案 6 :(得分:0)
我的界面不在测试项目中,但这是我如何使用 NUnit 和 Moq 实现的。
using Microsoft.AspNetCore.SignalR;
using Moq;
using NUnit.Framework;
namespace TestLibrary
{
// 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);
}
public class ProjectsHub : Hub<ISignals>
{
public void AddProject(string id)
{
Clients.All.AddProject(id);
}
}
public class ProjectsHubTests
{
[Test]
public void AddProject_Broadcasts()
{
// Arrange
ProjectsHub hub = new ProjectsHub();
var clients = new Mock<IHubCallerClients<ISignals>>();
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();
}
}
}