Подтвердить что ты не робот

Как насмехаться с веб-службой

Нужно ли мне переписать мой код, чтобы сделать это в интерфейсе? Или есть более простой способ? Я использую Moq

4b9b3361

Ответ 1

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

например:

public class ServiceAdapter: IServiceAdapter
{
    public void CallSomeWebMethod()
    {
        var someService = new MyWebService();
        someService.SomeWebMethod();
    }
}

Затем я просто закрою сервисный адаптер.

[Test]    
public void SomeMethod_Scenario_ExpectedResult()
{
    var adapterMock = new Mock<IServiceAdapter>();
    //do your test
}

Ответ 2

писал пару ответов об модульном тестировании и насмешливость в последнее время. Я писал в другом месте, что важно спросить себя, что именно вы тестируете. Что касается вашей конкретной ситуации, я надеюсь, что ответ будет "Я тестирую бизнес-логику, которую предоставляет мой 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 ();
    }
}

в prod

// 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
}

В общем случае, если зависимости класса являются службами in-proc, решение применить шаблон, такой как Injection Dependency [DI] или Inversion of Control [IoC], зависит от вас - и ваше желание изолировать и unit test эти услуги будут информировать ваш дизайн. Однако, если зависимости классов пересекают границу процесса, например Database или WebService, я настоятельно рекомендую применить эти шаблоны, как мы это делали выше.

Действительно, это просто старый интерфейс. Вы, наверное, уже видите, как это окупается.

:)

Ответ 3

I писал об этом давным-давно. В основном, используя частичные классы и немного усилий (автоматическое или ручное, в зависимости от того, как часто вы собираетесь менять веб-сервис), вы можете сделать прокси-класс веб-службы реализованным интерфейсом. Вы можете затем издеваться над ним как обычно.

Ответ 4

есть простой способ. например, если у нас есть класс WebService с именем DbService, сначала создайте для него интерфейс (например, IService) и используйте этот интерфейс для издевательств, затем добавьте класс в свой проект и поставьте это:

public partial class DbService:IService {

}

оставить класс пустым, поскольку веб-службы являются частичным классом, мы используем эту реализацию. (ранее