2015-05-21 2 views
0

редактировать Коррекция:Не может иметь две операции в том же контракте с тем же именем: Auto Сформирован Асинхронный метод

Моя ошибка в том, что вместо использования ChatService.IChatService я использую ReflectorLike.ChatServiceReference.IchatService.

Другими словами, AFAIU Я ссылался на ссылку на интерфейс, а не на интерфейс. (Если вы найдете лучший способ объяснить, что, пожалуйста, предложите их, я отредактирую ответ позже) Если вы используете ту же ошибку, убедитесь, что используете правильный интерфейс.

Выпуск:

Ошибка:

SetUp : System.InvalidOperationException : Cannot have two operations in the same contract with the same name, methods ClientConnectAsync and ClientConnect in type ReflectorLike.ChatReference.IChatService violate this rule. You can change the name of one of the operations by changing the method name or by using the Name property of OperationContractAttribute.

Резюме: Я пытался сделать это Recommended patterns for unit testing web services

Но моя издевались служба бросает мне исключение, потому что все мои методы имеют близнецы с таким же именем, например, у него есть как ClientCon Nect и 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"); 
     } 
    } 
} 

ответ

1

Я написал сообщение в блоге Hosting a Mock as a WCF service, который вы смотрели на то, чтобы создать MockServiceHostFactory.

Две вещи:

  1. Вам не нужно называть линию, чтобы исключить ServiceContractAttribute от копирования на макете объекта, это обрабатывается для вас NSubstitute.
  2. Должен быть какой-то код, который вы нам не дали, я взял ваш существующий код и запустил его локально, и он издевается.

Вот код, который у меня есть, который работает.

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

Можете ли вы показать недостающие кусочки кода, которые могут иметь важное значение, особенно если вы упростили его с целью задать вопрос? Можете ли вы включить трассировку стека, которая показывает, на какой строке вы действительно получаете ошибку?

+0

Спасибо за ваш ответ. Как вы можете видеть в моем ответе, я полностью сдался и пошел на что-то еще. После нескольких секунд назад, пытаясь снова, я обнаружил свою ошибку. Я ссылался на ссылку (это имеет смысл?) Вместо '#using myservice' я написал '#using myasp.myserviceReference'. Поэтому я использовал неправильный интерфейс ... :( – Lomithrani

1

Обманутым сервисом для целей тестирования был бы макет объекта с тем же интерфейсом, что и ваша служба, не обязательно полностью реализованная, или фактический объект ServiceHost как то, что вы пытаетесь сделать.

Я бы рекомендовал, чтобы все, что вы делаете, передало объект myMockedService, так как ваш клиентский код должен зависеть только от этого интерфейса - основная реализация не имеет значения (или должна быть) для целей модульного тестирования.

+0

Я не уверен, что полностью понял ваш ответ, но я думаю, что не могу сделать то, что вы предложили, поскольку я тестирую хакер signalR, который обращается к службе, но соединение с моей службой осуществляется через ссылку (I не имеют конструктора, где я подключаюсь к моему сервису) Я делаю это так: private readonly ChatServiceClient client = new ChatServiceClient(); Так что мне действительно нужно работать с ServiceHost, но я получаю сообщение об ошибке – Lomithrani

+0

Чтобы сделать его пригодным для тестирования, вам нужно будет абстрагироваться от конкретного класса 'ChatServiceClient' или создать оболочку, которая предоставляет объект' ChatServiceClient' через 'IChatService'. Ваш код концентратора должен зависеть и делать вызовы против объекта типа IChatService. В конце концов - то, что вы тестируете, - это то, что концентратор вызывает правильные методы в службе и правильно отвечает на данные из службы. Смысл всего стека WCF не нужен, и таким образом невозможно было бы издеваться над возвращаемыми значениями с помощью NSubstitute. Помните «D» принципов SOLID. – toadflakz

+0

Хорошо, я постараюсь изменить все это, но я до сих пор не могу понять, почему я получаю эту ошибку – Lomithrani

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