Comment se moquer de la WCF client à l'aide de Moq?
Dans mon projet, j'ai utilisé: SL5+ MVVM+ Prisme + FMC + Rx + Moq + Silverlight Framework de Test Unitaire.
Je suis nouveau à l'unité-des tests et ont récemment commencé en DI, les Modèles (MVVM) etc. Donc le code suivant a beaucoup de possibilités d'amélioration (n'hésitez pas à rejeter l'ensemble de l'approche que je prends si vous pensez que oui).
Pour accéder à mes services WCF, j'ai créé une classe factory comme ci-dessous (encore une fois, il peut être imparfaite, mais s'il vous plaît jetez un oeil):
namespace SomeSolution
{
public class ServiceClientFactory:IServiceClientFactory
{
public CourseServiceClient GetCourseServiceClient()
{
var client = new CourseServiceClient();
client.ChannelFactory.Faulted += (s, e) => client.Abort();
if(client.State== CommunicationState.Closed){client.InnerChannel.Open();}
return client;
}
public ConfigServiceClient GetConfigServiceClient()
{
var client = new ConfigServiceClient();
client.ChannelFactory.Faulted += (s, e) => client.Abort();
if (client.State == CommunicationState.Closed) { client.InnerChannel.Open(); }
return client;
}
public ContactServiceClient GetContactServiceClient()
{
var client = new ContactServiceClient();
client.ChannelFactory.Faulted += (s, e) => client.Abort();
if (client.State == CommunicationState.Closed) { client.InnerChannel.Open(); }
return client;
}
}
}
Il implémente une interface simple comme ci-dessous:
public interface IServiceClientFactory
{
CourseServiceClient GetCourseServiceClient();
ConfigServiceClient GetConfigServiceClient();
ContactServiceClient GetContactServiceClient();
}
Dans mes VMs je suis en train de faire DI de la classe ci-dessus et à l'aide de Rx appeler WCF comme ci-dessous:
var client = _serviceClientFactory.GetContactServiceClient();
try
{
IObservable<IEvent<GetContactByIdCompletedEventArgs>> observable =
Observable.FromEvent<GetContactByIdCompletedEventArgs>(client, "GetContactByIdCompleted").Take(1);
observable.Subscribe(
e =>
{
if (e.EventArgs.Error == null)
{
//some code here that needs to be unit-tested
}
},
ex =>
{
_errorLogger.ProcessError(GetType().Name, MethodBase.GetCurrentMethod().Name, ErrorSource.Observable, "", -1, ex);
}
);
client.GetContactByIdAsync(contactid, UserInformation.SecurityToken);
}
catch (Exception ex)
{
_errorLogger.ProcessError(GetType().Name, MethodBase.GetCurrentMethod().Name, ErrorSource.Code, "", -1, ex);
}
Maintenant je veux créer des tests unitaires (oui, ce n'est pas TDD). Mais je ne comprends pas par où commencer. Moq je ne peux pas se moquer de la BlahServiceClient. Aussi pas de svcutil interface généré peut aider parce que les méthodes asynchrones ne font pas partie de l'auto-générés IBlahService interface. Je préfèrent étendre (par le biais des classes partielles, etc) de l'auto généré des classes, mais je n'aimerais pas que d'opter pour la créer manuellement le code svcutil peut générer (franchement, compte tenu du temps et du budget).
Quelqu'un peut s'il vous plaît aider? Une aiguille dans la bonne direction serait m'aider beaucoup.
C'est très vrai Michal. Je devrais refactoriser mon code pour isoler la logique de la WCF appel. Merci beaucoup.
Il n'y a pas beaucoup de refactoriser ici. Il suffit de mettre votre "code" dans son propre méthode et de tester cette méthode. Pas besoin de tester la WCF choses, puis.
dans mon cas, j'ai juste fait de la création d'un service. Nous voulons l'unité de tests pour s'assurer de faire des appels via wsdl fonctionne toujours, donc nous avons besoin d'un sweet de tests. Donc, je suis en train de test unitaire mon service méthodes...comme si je suis un client de consommer le Service Web. Donc, mon intention est d'appeler les méthodes spécifiées dans le fichier WSDL comme un hypothétique client/consommateur de mon web service. Maintenant, d'autre part, j'pouvez également créer des tests unitaires dans mon projet de SErvice lui-même pour tester les méthodes? Pas sûr de ce que pour l'unité de test.
qu'est-ce que client.ChannelFactory faire?
OriginalL'auteur Dharmesh | 2012-12-27
Vous devez vous connecter pour publier un commentaire.
Quand se moquant de votre service client, vous êtes réellement en se moquant de l'une des interfaces qu'il implémente. Donc, dans votre cas, il peut être
IContactService
.Le code généré implémente à la fois
System.ServiceModel.ClientBase<IContactService>
etIContactService
. Votre dépendance fournisseur (dans votre cas, une usine) est de retourContactServiceClient
- changement de ceIContactService
pour les débutants. Cela vous aidera dans vos DI, maintenant et dans l'avenir.Ok, vous êtes déjà un résumé de l'usine et maintenant ils retourner votre interface de service
IContactService
. Vous êtes à l'aide des interfaces seulement maintenant si le moqueur est assez trivial.Tout d'abord, quelques hypothèses sur le code que vous essayez de faire de l'exercice. L'extrait de code fourni des messages à la fois le résumé de l'usine et le service client. À condition que le //du code ici que doit être l'unité testée l'article ne va pas interagir avec tous les autres dépendances alors vous êtes à la recherche pour se moquer à la fois l'usine et le service client de sorte que vous testez est isolé de tout le corps de la méthode de code.
J'ai fait un ajustement pour le bien de l'exemple. Vos interfaces:
Alors votre test de look résumant comme ceci:
EDIT: se moquer des Méthodes Asynchrones
Async généré méthodes ne font pas partie de vos méthodes de service et est créé par la WCF dans le cadre de la classe Client. Pour se moquer de ceux qu'une Interface, procédez de la manière suivante:
Extrait de l'Interface de la
ContactServiceClient
classe. VS, c'est tout simplement un clic droit (sur le nom de la classe), refactoriser, extrait de l'interface. Et ne choisir que les méthodes applicables.La
ContactServiceClient
classe est partielle afin de créer un nouveau fichier de classe et de redéfinir la ContactServiceClient classe pour mettre en œuvre la nouvelleIContactServiceClient
de l'interface que vous venez d'extraire.Comme tels et maintenant le client de la classe implémente ÉGALEMENT la nouvelle interface avec les méthodes asynchrones. Lors de l'actualisation de votre interface de service et la classe de service est re-généré - vous n'avez pas à re-extrait de l'interface que vous avez créé un partiels séparés classe avec la référence de l'interface.
Créer une nouvelle usine pour revenir à la nouvelle interface
Modifier le test pour travailler avec cette interface.
Vous n'avez pas à part le code de l'interface asynchrone pour obtenir le même résultat. Je vais l'ajouter à ma réponse
Merci encore Quinton.
Votre solution pour la Async problème est problématique, comme l'ensemble de l'idée de la génération de code, c'est qu'il "fonctionne". Si l'OP bascule à l'utilisation de la main-extrait ICourseServiceClient, alors la prochaine fois que l'IDL changements, il faudra ré-extraire l'interface afin d'utiliser les changements dans son code. Faisable - mais ennuyeux et sujette à erreur.
Réponse utile. Cependant, le "Contact" et "Cours" classes sont foiré dans votre code, relatives à la discussion de la question. Auriez-vous l'esprit en utilisant juste un de ces?
OriginalL'auteur Quinton Bernhardt