同一协定中不能有两个具有相同名称的操作:自动生成的异步方法
本文关键字:异步方法 自动生成 操作 不能 两个 | 更新日期: 2023-09-27 17:50:08
编辑更正:
我的错误是,我没有使用ChatService.IChatService,而是使用ReflectorLike.ChatServiceReference.IhatService.
换句话说,AFAIU我引用的是对接口的引用,而不是接口本身。(如果你能找到更好的解释方法,请建议他们,我稍后会编辑答案(如果在相同的错误中运行,请确保使用正确的接口。
问题:
错误:
SetUp:System.InvalidOperationException:不能有两个操作在具有相同名称的同一协定中,方法ClientConnectAsync和类型为ReflectorLike.ChatReference.IChatService的ClientConnect违反此规则。您可以通过以下方式更改其中一个操作的名称更改方法名称或使用的name属性OperationContractAttribute。
摘要:我试着这样做推荐模式单元测试web服务
但我的模拟服务给我带来了一个异常,因为我所有的方法都有同名的双胞胎——例如,它同时有ClientConnect和ClientConnectAsync,这违反了WCF服务规则
我有一个接口是的服务
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");
}
}
}
我写了一篇博客文章,将Mock作为WCF服务托管,您曾考虑过创建MockServiceHostFactory
。
两件事:
- 您不需要调用该行来排除
ServiceContractAttribute
被复制到mock对象,这是由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;
}
}
}
你能显示任何可能很重要的代码缺失部分吗?特别是如果你为了提问而简化了代码?你能包括堆栈跟踪来显示你实际在哪一行得到错误吗?
出于测试目的,模拟服务将是一个与您的服务具有相同接口的模拟对象,不一定完全实现,也不一定是您尝试做的实际ServiceHost
对象。
我建议您所做的就是传递myMockedService
对象,因为您的客户端代码应该仅依赖于该接口——底层实现与单元测试目的无关(或者应该是(。
根据toflakz的建议,我只是逐一嘲笑我的所有服务方法(我的服务很小,这不是一项很大的工作,但如果有更大的服务,你可能会遇到麻烦(我需要嘲笑很多事情,因为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
}
}
}