Comment se moquer d'un service web

Dois-je réécrire mon code pour faire cela dans une interface? Ou est-il un moyen plus facile? Je suis à l'aide Moq

25
demandé sur zachary 2009-10-23 22:14:36

4 réponses

ce que je fais habituellement est de construire un wrapper ou un adaptateur autour de mon service web et juste se moquer de cela.

par exemple:

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

alors je dois juste couper l'adaptateur de service.

[Test]    
public void SomeMethod_Scenario_ExpectedResult()
{
    var adapterMock = new Mock<IServiceAdapter>();
    //do your test
}
39
répondu Joseph 2009-10-23 18:17:12

j'ai écrit quelques réponses sur les tests unitaires et les moqueries dernièrement. Je l'ai écrit ailleurs qu'il est important de se demander ce exactement êtes-vous tester. En ce qui concerne votre situation particulière, j'espère que la réponse est "je teste la logique commerciale que mon service Web expose", et "je suis en train de tester mon WebService" - il y a une différence.


Si vos préoccupations sont côté serveur

vous faites pas besoin de tester les Services web en général. MS l'a déjà fait. Des Millions de personnes l'ont fait. Tester la couche transport, le protocole, la définition de WebServices est une perte de temps.

Vous devez cibler votre logique. La meilleure façon de le faire est de distinct votre logique d'affaires de votre service Web. Considérez les points suivants

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 ();
    }
}

il n'y a aucun moyen de tester cette logique sans invoquer directement le service Web. Quel que vous voulez vraiment est

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 ();
    }
}

en 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

// test business logic without web service! yay!
[Test]
public void Test_DoSomething ()
{
    MyService service = new MyService ();
    string actual = service.DoSomething ();
    // verify results
}

la gestion des dépendances [comme le membre du service D'authentification] est une question distincte. Cependant, ce qui rend votre WebMethods simple passthroughs pour corriger les classes d'affaires sous-jacentes et leur enlever complètement la logique, vous permet de cibler le "vrai" code utilisateur par opposition à la plomberie de votre implémentation WebService typique.


si vos préoccupations sont côté client

Vous avez une entreprise composant appeler un service web, et je suis d'accord que vous ne voulez pas créer un client pour les tests unitaires.

public partial class MyWebService :
    System.Web.Services.Protocols.SoapHttpClientProtocol 
{
    ...
    public string DoSomething () { ... }
}

public class MyClient
{
    public void CallService ()
    {
        MyWebService client = new MyWebService ();
        client.DoSomething ();
    }
}

ici, vous avez des problèmes de dépendance, à savoir que vous ne pouvez pas tester MyClient.CallService sans instanciation et hébergement de votre service Web. Particulièrement déconcertant si vous ne possédez pas ou animateur de service à distance. Dans ce cas, oui, vous devriez écrire contre une interface-une fois de nouveau pour séparer et isoler la logique métier.

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

[Test]
public void Test_CallService ()
{
    IMyWebService mockService = null;
    // instantiate mock with expectations
    MyClient client = new MyClient (mockService);
    client.CallService ();
    // verify results
}

en général, si les dépendances d'une classe sont des services in-proc, la décision d'appliquer un modèle comme L'Injection de dépendances [DI] ou L'Inversion du contrôle [IoC] vous appartient - et votre désir d'isoler et de tester à l'Unité ces services guidera votre conception. Toutefois, si les dépendances d'une classe franchissent la limite de processus, par exemple Base de données ou WebService, I highly recommander l'application de ces modèles comme nous l'avons fait ci-dessus.

vraiment, c'est juste un simple développement d'interface. Tu as probablement déjà vu comment ça porte ses fruits.

:)

33
répondu johnny g 2012-08-16 13:58:04

I blogué à ce sujet il y a longtemps. Essentiellement en utilisant des classes partielles et un peu d'effort (soit automatisé ou manuel, selon la fréquence à laquelle vous allez changer le service web), vous pouvez faire la classe proxy de service web mettre en œuvre une interface. Vous pouvez ensuite s'en moquer comme d'habitude.

10
répondu Jon Skeet 2014-08-05 12:07:44

il existe un moyen facile. par exemple si nous avons Classe WebService avec le nom DbService, créez d'abord une interface (ex. IService), et utilisez cette interface pour vous moquer, puis ajoutez une classe à votre projet et mettez ceci:

public partial class DbService:IService {

}

laisser la classe vide, en raison des services web sont partiels classe nous utilisons cette implémentation. (précédemment

2
répondu SalmanAA 2011-10-09 11:49:59