писал пару отзывов о юнит-тестировании и издевательствах в последнее время. Я написал в другом месте, что важно спросить себя, что именно вы тестируете. Что касается вашей конкретной ситуации, я надеюсь, что ответ «я проверяю бизнес-логику, которую предоставляет мой WebService», а не «я проверяю мой WebService» - есть разница.
Если ваши проблемы на стороне сервера
Вам не нужно тестировать WebServices в целом. MS уже сделала это. Миллионы людей сделали это. Тестирование транспортного уровня, протокола, определения WebServices - пустая трата времени.
Вам нужно настроить свою бизнес-логику . Лучший способ сделать это - отделить вашу бизнес-логику от вашего WebService. Рассмотрим следующее
public class MyWebSevice : System.Web.Services.WebService
{
private AuthenticationService _auth = new AuthenticationService ();
private int _count = 0;
[WebMethod]
public string DoSomething ()
{
// embedded business logic, bad bad bad
if (_auth.Authenticate ())
{
_count++;
}
return count.ToString ();
}
}
нет способа проверить эту логику, не вызывая WebService напрямую. То, что вы действительно хотите, это
public class MyService
{
// keeners will realise this too should be injected
// as a dependency, but just cut and pasted to demonstrate
// isolation
private AuthenticationService _auth = new AuthenticationService ();
private int _count = 0;
public string DoSomething ()
{
if (_auth.Authenticate ())
{
_count++;
}
return count.ToString ();
}
}
в продукт
// this web service is now a consumer of a business class,
// no embedded logic, so does not require direct testing
public class MyWebSevice : System.Web.Services.WebService
{
private readonly MyService _service = new MyService ();
[WebMethod]
public string DoSomething ()
{
_service.DoSomething ();
}
}
в тесте
// test business logic without web service! yay!
[Test]
public void Test_DoSomething ()
{
MyService service = new MyService ();
string actual = service.DoSomething ();
// verify results
}
управление зависимостями [например, член AuthenticationService] является отдельной проблемой. Однако, делая ваши WebMethods простыми проходами для правильных базовых бизнес-классов и полностью удаляя из них логику, вы сможете ориентироваться на «настоящий» пользовательский код, а не на обычную реализацию вашей WebService.
Если ваши проблемы на стороне клиента
У вас есть бизнес-компонент , вызывающий веб-сервис, и я согласен, что вы не хотите создавать клиента для модульного тестирования.
public partial class MyWebService :
System.Web.Services.Protocols.SoapHttpClientProtocol
{
...
public string DoSomething () { ... }
}
public class MyClient
{
public void CallService ()
{
MyWebService client = new MyWebService ();
client.DoSomething ();
}
}
Здесь у вас есть проблемы с зависимостями, а именно вы не можете протестировать MyClient.CallService без создания экземпляра и размещения вашего WebService. Особенно неприятно, если вы не являетесь владельцем или хостом указанного удаленного сервиса. В этом случае, да, вы должны написать против интерфейса - еще раз, чтобы отделить и изолировать бизнес-логику.
public interface IMyWebService
{
string DoSomething ();
}
public class MyWebServiceWrapper : IMyWebService
{
public string DoSomething ()
{
MyWebService client = new MyWebService ();
client.DoSomething ();
}
}
public class MyClient
{
private readonly IMyWebService _client = null;
public MyClient () : this (new MyWebServiceWrapper ()) { }
public MyClient (IMyWebService client)
{
_client = client;
}
public void CallService ()
{
_client.DoSomething ();
}
}
в тесте
[Test]
public void Test_CallService ()
{
IMyWebService mockService = null;
// instantiate mock with expectations
MyClient client = new MyClient (mockService);
client.CallService ();
// verify results
}
Как правило, если зависимости класса являются внутрипроцессными службами, решение о применении шаблона, такого как Dependency Injection [DI] или Inversion of Control [IoC], остается за вами - и вы хотите изолировать и выполнить модульное тестирование этих служб. сообщу ваш дизайн. Однако, если зависимости класса пересекают границу процесса , например, Database или WebService, я настоятельно рекомендую применять эти шаблоны, как мы это делали выше.
Действительно, это просто разработка старого интерфейса. Вы, наверное, уже видите, как это окупается.
:)