编辑更正:
我的错误是我没有使用ChatService.IChatService,而是使用了ReflectorLike.ChatServiceReference.IchatService。
换句话说,AFAIU 我引用了一个引用到接口而不是它自己的接口。 (如果你找到更好的解释方法,请建议他们我以后编辑答案) 如果您运行相同的错误,请确保使用正确的接口。
问题:
错误:
SetUp:System.InvalidOperationException:不能有两个操作 在具有相同名称的同一合同中,方法ClientConnectAsync 和ClientConnect类型为ReflectorLike.ChatReference.IChatService 违反这条规则。您可以更改其中一个操作的名称 更改方法名称或使用Name属性 OperationContractAttribute。
要点: 我试着这样做Recommended patterns for unit testing web services
但是我的模拟服务抛出了一个例外,因为我的所有方法都有同名的双胞胎,例如它同时具有违反WCF服务规则的ClientConnect和ClientConnectAsync
我有一个接口是
的服务namespace ChatService
{
[ServiceContract]
public interface IChatService
{
[OperationContract]
ChatUser ClientConnect(string userName);
[OperationContract]
void SendNewMessage(ChatMessage newMessage);
[OperationContract]
List<ChatUser> GetAllUsers();
[OperationContract]
void RemoveUser(ChatUser user);
[OperationContract]
List<ChatMessage> GetNewMessages(ChatUser user);
}
[DataContract]
public class ChatMessage
{
[DataMember]
public ChatUser User { get; set; }
[DataMember]
public string Message { get; set; }
private DateTime date;
[DataMember]
public DateTime Date
{
get { return date; }
set { date = value; }
}
}
/// <summary>
///
/// </summary>
[DataContract]
public class ChatUser
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public string IpAddress { get; set; }
[DataMember]
public string HostName { get; set; }
public ChatUser(string userName)
{
this.UserName = userName;
}
public override string ToString()
{
return this.UserName;
}
}
}
我想使用模拟服务测试我的客户端,所以我用nunit和nsubstitute测试它
namespace ReflectorLike.Tests
{
[TestFixture]
internal class ChatHubTester
{
private ChatHub hub;
private ServiceHost host;
private IChatService myMockedService;
[SetUp]
public void SetUp()
{
Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add<ServiceContractAttribute>();
myMockedService = Substitute.For<IChatService>();
host = MockServiceHostFactory.GenerateMockServiceHost(myMockedService, new Uri("http://localhost:12345"), "ServiceEndPoint");
host.Open();
hub=new ChatHub();
}
[TearDown]
public void TearDown()
{
host.Close();
}
[Test]
public void SomeTest()
{
hub.Connect("Test");
}
}
}
答案 0 :(得分:1)
用于测试目的的模拟服务将是一个模拟对象,其接口与您的服务相同,不一定完全实现,或者是您尝试执行的实际ServiceHost
对象。
我建议您所做的就是传递myMockedService
对象,因为您的客户端代码应仅依赖于该接口 - 底层实现与单元测试目的无关(或应该是)。
答案 1 :(得分:1)
我撰写了您要查看的博文Hosting a Mock as a WCF service以创建MockServiceHostFactory
。
两件事:
ServiceContractAttribute
被复制到模拟对象,这是由NSubstitute为您处理的。这是我的代码。
class Foo
{
[Test]
public void Should_work()
{
var myWcfServiceMock = Substitute.For<IChatService>();
var mockServiceHost = MockServiceHostFactory.GenerateMockServiceHost(myWcfServiceMock , new Uri("http://localhost:8001"), "MyService");
mockServiceHost.Open();
mockServiceHost.Close();
}
public static class MockServiceHostFactory
{
public static ServiceHost GenerateMockServiceHost<TMock>(TMock mock, Uri baseAddress, string endpointAddress)
{
var serviceHost = new ServiceHost(mock, new[] { baseAddress });
serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;
serviceHost.AddServiceEndpoint(typeof(TMock), new BasicHttpBinding(), endpointAddress);
return serviceHost;
}
}
}
您是否可以显示任何可能重要的代码,特别是如果您为了提出问题而对其进行了简化?您是否可以包含堆栈跟踪,以显示您实际收到错误的哪一行?
答案 2 :(得分:0)
按照toadflakz建议,我只是逐个模拟我的所有服务方法(我的服务很小,不是很多工作,但服务更大,你可能会遇到麻烦) 我需要嘲笑很多东西,因为signalR,服务,集线器,上下文......:
namespace ReflectorLike.Tests
{
[TestFixture]
internal class ChatHubTester
{
[SetUp]
public void SetUp()
{
var request = Substitute.For<IRequest>();
request.User.Identity.Name.Returns("IdentityName");
var clients = Substitute.For<IHubCallerConnectionContext<ExpandoObject>>();
clients.Group("groupName").Returns(new ExpandoObject());
var groupManager = Substitute.For<IGroupManager>();
context = Substitute.For<HubCallerContext>(request, "123");
context.ConnectionId.Returns(rank.ToString(CultureInfo.InvariantCulture));
myMockedClient = Substitute.For<IChatService>();
myMockedClient.When(x => x.RemoveUser(Arg.Any<ChatUser>())).DoNotCallBase();
myMockedClient.When(x => x.SendNewMessage(Arg.Any<ChatMessage>())).DoNotCallBase();
var testList = new List<ChatMessage> { new ChatMessage { Message = "Test Message", User = new ChatUser{ UserName = "LastUser"}} }.ToArray();
myMockedClient.GetNewMessages(Arg.Any<ChatUser>()).Returns(testList);
UpdateClientConnect(false);
hub = Substitute.ForPartsOf<ChatHub>(myMockedClient, context, groupManager);
hub.When(x => x.Broadcast(Arg.Any<ChatMessage>())).DoNotCallBase();
hub.When(x => x.EmitTo(Arg.Any<string>(), Arg.Any<ChatMessage>())).DoNotCallBase();
}
public void UpdateClientConnect(bool last)
{
myMockedClient.ClientConnect(Arg.Any<string>()).Returns(new ChatUser { UserName = "TestUser" + rank }).AndDoes(x =>
{
context.ConnectionId
.Returns(
rank
.ToString
(CultureInfo
.InvariantCulture));
if (!last)
{
rank ++;
}
});
}
private HubCallerContext context;
private IChatService myMockedClient;
private ChatHub hub;
private static int rank;
private const bool LAST = true;
private const bool NOTLAST = false;
[Test]
public void Connect()
{
hub.Connect("0");
UpdateClientConnect(LAST);
hub.Connect("1");
int i = 0;
foreach (ICall call in hub.ReceivedCalls())
{
Assert.AreEqual("TestUser" + i + " connected", ((ChatMessage)(call.GetArguments()[0])).Message);
Assert.AreEqual("SYSTEM", ((ChatMessage)(call.GetArguments()[0])).User.UserName);
i++;
}
Assert.AreEqual(2, i); // 2 items
}
}
}