2016-11-21 1 views
1

Я хочу протестировать свой класс, который вызывает сторонний веб-сервис. Можно ли использовать FakeItEasy для этого?Fake WCF-Service звонки с FakeItEasy

Wenn Я пытаюсь подделать класс от Reference.cs (сгенерирован автоматически), UnitTest начался и не возвращается.

Reference.cs (автогенерируемая)

[System.Diagnostics.DebuggerStepThroughAttribute()] 
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] 
    public partial class ws_AccessoryClient : System.ServiceModel.ClientBase<AccessoryService.ws_Accessory>, 
     AccessoryService.ws_Accessory 
    { 
     public ws_AccessoryClient() 
     { 
     } 

     public ws_AccessoryClient(string endpointConfigurationName) : 
      base(endpointConfigurationName) 
     { 
     } 

     public AccessoryService.ResponseMessageOf_ListOf_SomeMethodInfo SomeMethod(
      AccessoryService.RequestMessageOf_SomeMethod request) 
     { 
      return base.Channel.SomeMethod(request); 
     } 
    } 

Test.cs

[Test] 
    public void DoBusinessLogicTryTest() 
    { 
     var accessoryProxy = A.Fake<ws_AccessoryClient>(); 
    } 
+0

В общем, поддельные классы (а не интерфейсы) могут быть сложными, потому что сгенерированная подделка должна вызывать не виртуальное поведение исходного класса. Возможно, это то, что здесь происходит. Рассмотрим отладку теста, а затем «Разбить все», чтобы увидеть, где он застрял. Тогда, может быть, мы сможем найти лучший ответ, основанный на том, что мы узнаем. –

ответ

2

Вы не можете (и почему вы хотите?).

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

interface ICallTheService 
{ 
    void CallTheService(); 
} 

class ServiceCaller : ICallTheService 
{ 
    void CallTheService() 
    { 
     // Call the service... 
    } 
} 

Тогда вы можете подделать этот класс и убедитесь, что ваш класс тестируемой вызывает операцию CallTheService.

// fake the service caller and pass it into your service 
var serviceCaller = A.Fake<ICallTheService>(); 

// Verify invocation 
A.CallTo(() => serviceCaller.CallTheService()).MustHaveHappened(); 

Я хочу, чтобы проверить логику в моем классе, зависит от ответа от WCF-службы

Это где я думаю, что вы собираетесь плохим разделением проблем. Ваш тест называется DoBusinessLogicTryTest, но он имеет зависимость от System.ServiceModel, который относится к инфраструктуре. Ваша бизнес-логика должна тестироваться без этой зависимости. Если ваш класс испытуемого должно вести себя по-разному в зависимости от ответа, вы могли бы сделать что-то вроде этого:

interface ICallTheService 
{ 
    ServiceResponseModel CallTheService(); 
} 

enum ServiceResponseModel 
{ 
    Success, 
    PartialSuccess, 
    FailureCondition1, 
    FailureCondition2, 
    // etc... 
} 

Тогда вы можете прокачать поддельное ICallTheService вернуть каждый из возможных ответов и проверить ваш класс на этом основании.

A.CallTo(() => serviceCaller.CallTheService()).Returns(ServiceResponseModel.Success); 

Для примера, если некоторые исключения (определенные в WCF) обрабатываются правильно

Это также ничего общего с бизнес-логикой. Ответственность за обработку исключений лежит на реализации ICallTheService. Фактически, я бы представил для этого еще один класс, задачей которого было бы перевести various possible exceptions из System.ServiceModel в вашу модель ответа. Например:

class WCFErrorResponseTranslator 
{ 
    ServiceResponseModel TranslateWCFException (Exception ex) 
    { 
     if (ex.GetType() == typeOf(TimeoutException)) { return ServiceResponseModel.TimeOut; } 
     /// etc 
    } 
} 

Такое поведение можно затем протестировать изолированно.

+0

Я хочу проверить логику в своем классе, зависит от ответа от WCF-Service. Например, если некоторые Исключения (определенные в WCF) обрабатываются правильно. Конечная точка (System.ServiceModel.Description.ServiceEndpoint) также устанавливается в классе и может быть сфальсифицирована в тесте. Спасибо. –

+0

@AnnyIgi См. Обновление моего ответа. –

+0

Спасибо! Я попробую! –

3

Как уже упоминалось, вы, возможно, не захотите делать то, что вы намерены использовать для модульного тестирования, поскольку это вызовет больше шума, чем это необходимо для модульного теста, который мог бы использовать издевавшиеся интерфейсы. Однако это эффективный подход для тестирования интеграции, это позволит вам проверить, работает ли ваша проводка WCF так, как вы ожидаете. Это также позволяет вам протестировать ваше приложение в целом, если вы принимаете более стильный стиль тестирования, где вы хотите макетировать как можно меньше.

Я использую этот подход для разворачивания поддельных конечных точек, используя NSubstitute, который описан в моем блоге Hosting a Mock as a WCF service. Главное, что вам нужно сделать, это развернуть ServiceHost, дать ему адрес конечной точки, который вы хотите использовать, установить режим контекста на одиночный и предоставить макет, который вы хотите использовать в качестве конечной точки.

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

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

После просмотра вашего примера вы можете захотеть использовать WCF ChannelFactory для создания своего клиента вместо использования конкретного класса клиента-прокси. ChannelFactory создает прокси «на лету» с помощью интерфейса, который вы предоставляете, и позволяя вводить прокси-сервер в свои зависимости с помощью интерфейса службы. Это упростит модульное тестирование и даст вам более развязанный дизайн.

+0

Соглашаться полностью на завод каналов вместо ссылки на обслуживание –