Модульное тестирование системы SOA WCF, в которой трудно получить достойное покрытие

В настоящее время мы заменяем 20-летнюю систему на основе C современной системой SOA WCF, построенной на .NET3.5. Наша отрасль требует тщательного тестирования, в том числе хорошего автоматизированного модульного тестирования. У нас есть проблемы, однако модульное тестирование нашей системы SOA близко к той степени, в которой система на основе C была модульным тестированием.

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

Запуск любых модульных тестов в Visual Studio практически невозможен, так как выполнение практически любых действий приводит к каким-либо межсервисным вызовам. Если это не доступ к данным, это одна из других служб. Я думаю, что мы можем получить около 5% охвата.

Я вижу, что многие люди борются с тестированием SOA, поэтому я полагаю, что это не уникально для нас. Дело в том, что QA задастся вопросом, почему мы не проводим модульное тестирование системы.

Честно говоря, я рассматриваю модульное тестирование VSTS скорее как регрессионное тестирование, чем как инструмент проверки (пригодности к использованию). Какие варианты существуют для модульного тестирования SOA? Реально ли по опыту людей добиться хорошего охвата? Есть ли способ издеваться над службой доступа к данным (или любой службой: ПРИМЕЧАНИЕ, мы не используем прокси-серверы WCF) или мы должны объяснить QA, что способность модульного тестирования за последние 20 лет ушла в прошлое...

Любые предложения приветствуются, я думаю, это вопрос общего мнения.


person MrLane    schedule 01.03.2010    source источник


Ответы (3)


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

Модульные тесты не должны выходить за границы службы. На самом деле идея сервиса заключается в том, что он полностью независим и непрозрачен. Вы тестируете службу напрямую — не по каналу WCF, а путем модульного тестирования реальных классов, составляющих службу. После того, как вы протестировали саму службу (которую вы должны обеспечить почти 100%-ным охватом), вам не нужно задействовать ее в тестах на стороне клиента.

Для модульных тестов на стороне клиента вы издеваетесь над сервисом. WCF на самом деле делает это очень простым для вас, потому что каждый клиент WCF реализует интерфейс; если вы обычно используете FooService или FooServiceSoapClient в своем коде, измените его, чтобы использовать соответствующие IFooService или FooServiceSoap, которые реализует прокси-класс. Затем вы можете написать свой собственный MockFooService, реализующий тот же интерфейс, и использовать его в своих клиентских тестах.

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

Дуплекс немного сложнее, но имейте в виду, что дуплексные сервисы также должны основываться на интерфейсах; даже пример MSDN представляет ICalculatorDuplexCallback. Обратные вызовы будут интерфейсами, поэтому так же, как вы можете смоделировать методы службы на стороне клиента, вы можете смоделировать обратные вызовы клиента на стороне службы. Просто используйте фиктивные/фальшивые обратные вызовы, которые вы используете для модульных тестов службы.

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

person Aaronaught    schedule 02.03.2010

Похоже, что сейчас вы проводите интеграционные тесты или системные тесты. Где методы тестирования вызывают внешние источники. Чтобы действительно выполнить модульное тестирование службы, вам нужно каким-то образом абстрагировать внешние вызовы, чтобы вы могли имитировать (например, moq) или заглушить вызовы этой службы.

Например, код, тесно связанный со службой доступа к данным:

public class SomeSOA
{
 public bool DoSomeDataAccess()
 {
  //call the real data service
  DataService dataService = new DataService()
  int getANumber = dataService.GetANumber();
  return getANumber == 2;
 }
}

Небольшой рефакторинг, чтобы уменьшить связь с DataService.

public class SomeSOA
{
 IDataService _dataService;
 public SomeSOA(IDataService dataService)
{
  _dataService = dataService;
}
public SomeSOA() :this(new DataServiceWrapper()){}
 public bool DoSomeDataAccess()
 {
  int getANumber = _dataService.GetANumber();
  return getANumber == 2;
 }
}

public DataServiceWrapper : IDataService
{
  public int GetANumber()
  {
   // call the real data service
  }
}

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

[TestMethod]
public void GetANumber_WithAValidReturnedNumber_ReturnsTure()
{

  IDataService dataService = new DataServiceFake();
  SomeSOA someSoa = new SomeSOA(dataService);
  Assert.IsTrue(someSoa.DoSomeDataAccess();
}

public class DataServiceFake :IDataService
{
  public int DoSomeDataAccess()
  {
    //return a fake result from the dataService.
    return 2;
  }
}

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

Надеюсь, это поможет и имеет смысл!

person Mark Coleman    schedule 02.03.2010

Вот мое предложение: отойдите от парадигмы «модульного тестирования» и поработайте над набором интеграционных тестов.

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

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

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

Возможно, вам придется создать еще одну службу, которая обслуживает интеграционные тесты, очищая базу данных по запросу. (Очевидно, вы бы на самом деле не развернули это...)

Хотя они не являются «модульными тестами», вы получите полное покрытие.

person Andrew Shepherd    schedule 02.03.2010
comment
Я должен добавить, что еще больше усложняет это то, что многое из того, что мы делаем, — это публикация-подписка по контрактам обратного вызова WCF. Многое асинхронно. Тем не менее, то, что вы опубликовали, имеет большой смысл, и мы действительно можем провести много наших тестов таким образом. В нашей модели pub-sub многие обновления подписки, передаваемые от службы к клиенту, фактически инициируются действиями пользователя (которые отправляются в наши службы в виде командных сообщений через WCF), поэтому, несмотря на то, что мы являемся pub-sub, мы все еще очень часто запрашиваем ответ. в некотором смысле: когда что-то отправляется, мы ожидаем ответа. - person MrLane; 02.03.2010