Рекомендуемые шаблоны для модульного тестирования веб-сервисов
Мы собираемся начать разработку сервис-ориентированной среды (SOA), которая, безусловно, будет включать большое количество гранулированных веб-сервисов (REST в WCF). Мы достаточно дисциплинированы в модульном тестировании нашей клиентской и серверной кодовой базы, однако у нас нет большого опыта в модульном тестировании веб-сервисов. Мы действительно ищем руководство относительно того, где должны быть написаны тесты, и рекомендации о том, какой подход использовать при модульном тестировании наших сервисов.
Должны ли мы писать тесты, которые делают http-запросы и утверждают, что ответы должны быть такими, какими они должны быть? Должны ли мы сосредоточиться только на тестировании внутренней логики самих сервисных методов и не беспокоиться о тестировании реальных запросов? Или мы должны сделать оба? Есть ли другие рекомендации для того, что мы должны тестировать?
Мы действительно ищем объяснения и рекомендации и будем благодарны за любые советы, которые мы можем получить.
2 ответа
Я обнаружил, что тестирование веб-сервисов, в частности клиента и сервера WCF, полезно в дополнение к обычному модульному тестированию в следующих сценариях:
- Приемочное тестирование, при котором вы хотите черный ящик, тестируйте весь свой сервис и высовываетесь в конечности.
- Тестирование определенного соединения WCF, расширения, поведения и т. Д.
- Проверка правильности настройки вашего интерфейса и членов данных.
Большую часть времени я пытаюсь использовать очень простую настройку с базовым 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>();
Ну, в принципе, я думаю, что вам нужно иметь стратегию тестирования из двух частей.
Первая часть была бы настоящими модульными тестами, которые включали бы тестирование классов, полностью независимых от любого веб-запроса... так как основное определение модульного теста - это то, которое выполняется без необходимости в дополнительных средах или настройках, отличных от указанных в проверить себя.
Таким образом, вы будете создавать проекты модульных тестов, в которых вы будете создавать экземпляры классов кода ваших служб WCF, чтобы убедиться, что логика верна, во многом так же, как вы тестируете остальные классы.
Вторая часть будет набором интеграционных тестов, которые будут тестировать ваше приложение сквозным образом. Конечно, здесь вам нужна вся энчилада, веб-сервер, база данных и так далее.
Таким образом, вы знаете, что ваша логика точна, а также что ваше приложение работает.