在同一个具有相同名称的合同中不能有两个操作:自动生成的异步方法

时间:2015-05-21 09:19:29

标签: c# wcf nunit nsubstitute

编辑更正:

我的错误是我没有使用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");
        }
    }
}

3 个答案:

答案 0 :(得分:1)

用于测试目的的模拟服务将是一个模拟对象,其接口与您的服务相同,不一定完全实现,或者是您尝试执行的实际ServiceHost对象。

我建议您所做的就是传递myMockedService对象,因为您的客户端代码应仅依赖于该接口 - 底层实现与单元测试目的无关(或应该是)。

答案 1 :(得分:1)

我撰写了您要查看的博文Hosting a Mock as a WCF service以创建MockServiceHostFactory

两件事:

  1. 您不需要调用该行来排除ServiceContractAttribute被复制到模拟对象,这是由NSubstitute为您处理的。
  2. 必须有一些你没有给我们的代码,我已经拿走你现有的代码并在本地运行它并且它很好。
  3. 这是我的代码。

    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
        }
    }
}