Рекомендуемые шаблоны для модульного тестирования веб-сервисов - PullRequest
8 голосов
/ 06 марта 2012

Мы собираемся начать разработку сервис-ориентированной среды (SOA), которая, безусловно, будет включать большое количество гранулированных веб-сервисов (REST в WCF).Мы были достаточно дисциплинированы в модульном тестировании нашей клиентской и серверной кодовой базы, однако у нас нет большого опыта в модульном тестировании веб-сервисов.Мы действительно ищем руководство относительно того, где должны быть написаны тесты, и рекомендации о том, какой подход использовать при модульном тестировании наших сервисов.

Должны ли мы писать тесты, которые делают http-запросы и утверждают, что ответы - это то, что онидолжно быть?Должны ли мы сосредоточиться на тестировании внутренней логики самих сервисных методов и не беспокоиться о тестировании реальных запросов?Или мы должны сделать оба?Существуют ли другие рекомендации для того, что мы должны тестировать?

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

Ответы [ 2 ]

11 голосов
/ 25 апреля 2012

Я обнаружил, что тестирование веб-служб, в частности клиента и сервера WCF, полезно в дополнение к обычному модульному тестированию в следующих сценариях:

  1. Приемочное тестирование, при котором вы хотите, чтобы черный ящик проверял весь ваш сервис и высовывал вещи в конечности.
  2. Тестирование определенного соединения WCF, расширения, поведения и т. Д.
  3. Проверка правильности настройки интерфейса и членов данных.

Большую часть времени я пытаюсь использовать очень простую настройку с базовым http и связывать все в коде. Если я не провожу интеграционное или приемочное тестирование, я не тестирую клиента на сервере, вместо этого я имитирую одно из них, чтобы проверить другое изолированно. Ниже приведены примеры того, как я тестирую клиентов и сервисы WCF:

public static ServiceHost CreateServiceHost<TServiceToHost>(TServiceToHost serviceToHost, Uri baseAddress, string endpointAddress)
{
    var serviceHost = new ServiceHost(serviceToHost, new[] { baseAddress });

    serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
    serviceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>().InstanceContextMode = InstanceContextMode.Single;

    serviceHost.AddServiceEndpoint(typeof(TServiceToHost), new BasicHttpBinding(), endpointAddress);

    return serviceHost;
}

//Testing Service

[TestFixture]
class TestService
{
    private ServiceHost myServiceUnderTestHost;
    private ChannelFactory<IMyServiceUnderTest> myServiceUnderTestProxyFactory;
    [SetUp]
    public void SetUp()
    {
        IMyServiceUnderTest myServiceUnderTest = new MyServiceUnderTest();
        myServiceUnderTestHost = CreateServiceHost<IMyServiceUnderTest>(myServiceUnderTest, new Uri("http://localhost:12345"), "ServiceEndPoint");
        myServiceUnderTestHost.Open();

        myServiceUnderTestProxyFactory = new ChannelFactory<IMyServiceUnderTest>(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345/ServiceEndPoint")); 
    }

    [TearDown]
    public void TearDown()
    {
        myServiceUnderTestProxyFactory.Close();
        myServiceUnderTestHost.Close();
    }

    [Test]
    public void SomeTest() 
    {
        IMyServiceUnderTest serviceProxy = myServiceUnderTestProxyFactory.CreateChannel();

        serviceProxy.SomeMethodCall();
    }
}

//Testing Client

[TestFixture]
class TestService
{
    private ServiceHost myMockedServiceUnderTestHost;
    private IMyServiceUnderTest myMockedServiceUnderTest;

    [SetUp]
    public void SetUp()
    {
        myMockedServiceUnderTest = Substitute.For<IMyServiceUnderTest>(); //Using nsubstitute
        myServiceUnderTestHost = CreateServiceHost<IMyServiceUnderTest>(myMockedServiceUnderTest, new Uri("http://localhost:12345"), "ServiceEndPoint");
        myServiceUnderTestHost.Open();
    }

    [TearDown]
    public void TearDown()
    {
        myServiceUnderTestHost.Close();
    }

    [Test]
    public void SomeTest() 
    {
        //Create client and invoke methods that will call service
        //Will need some way of configuring the binding
        var client = new myClientUnderTest();

        client.DoWork();

        //Assert that method was called on the server
        myMockedServiceUnderTest.Recieved().SomeMethodCall();
    }
}

Примечание

Я забыл упомянуть, что если вы хотите смоделировать службу WCF, используя что-либо, использующее динамический прокси-замок, вам нужно будет предотвратить копирование ServiceContractAttribute в макет. У меня есть сообщение в блоге об этом, но в основном вы регистрируете атрибут как атрибут, предотвращающий репликацию перед созданием макета.

Castle.DynamicProxy.Generators.AttributesToAvoidReplicating
  .Add<ServiceContractAttribute>();
3 голосов
/ 25 апреля 2012

Ну, в принципе, я думаю, что вам нужно иметь стратегию тестирования, состоящую из двух частей.

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

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

Вторая часть будет набором интеграционных тестов, которые будутПротестируйте ваше приложение сквозным способом.Конечно, здесь вам нужна вся энчилада, веб-сервер, база данных и т. Д.

Таким образом, вы знаете, что ваша логика точна, а также что ваше приложение работает.

...