2017-03-12 3 views
3

J'ai quelques problèmes pour tester un singleton. Lorsque j'exécute ce code, j'obtiens une erreur dans TestGetLogicalDevices(). CallTo() a échoué car le service n'est pas un faux objet. Lorsque j'essaye de créer un faux objet (code commenté), cela donne une erreur car RestService est un singleton avec un constructeur privé. Comment puis-je créer un faux objet de ce singleton?Faux singleton avec FakeItEasy

private RestService service; 

    [TestInitialize] 
    public void Init() 
    { 
     //service = A.Fake<RestService>(); 
     service = RestService.Instance; 
     service.CreateClient("test", "test"); 
    } 

    [TestMethod] 
    public async Task TestGetLogicalDevices() 
    { 
     var logicalDevices = (List<LogicalDevice>)A.CollectionOfFake<LogicalDevice>(10); 
     A.CallTo(() => service.GetLogicalDevices()).Returns(Task.FromResult(logicalDevices)); 
     List<LogicalDevice> collectedData = await service.GetLogicalDevices(); 
     Assert.AreEqual(2, collectedData.Count); 
    } 

    public async Task<List<LogicalDevice>> GetLogicalDevices() 
    { 
     var response = await client.GetAsync(apiBaseUrl + "/logical-devices"); 
     if (response.IsSuccessStatusCode) 
     { 
      var json = await response.Content.ReadAsStringAsync(); 
      var logicalDevices = JsonConvert.DeserializeObject<List<LogicalDevice>>(json); 
      var sortedList = logicalDevices.OrderBy(logicalDevice => logicalDevice.Name).ToList(); 
      return sortedList; 
     } 
     else 
     { 
      return null; 
     } 
    } 

Mise à jour j'ai ajouté le code de ma méthode que je veux tester. Peut-être que quelqu'un a des suggestions pour de meilleurs tests?

+0

Veuillez indiquer le code de RestService, au moins les bits pertinents. –

+0

Vous ne pouvez pas amorcer une classe concrète pour qu'elle se comporte comme vous le souhaitez en utilisant un cadre de simulation. C'est à ça que servent les faux. Ce sont de fausses versions de dépendances qui peuvent être utilisées pour tester les classes qui en dépendent.Ce n'est pas clair ce que vous essayez d'affirmer avec ce test. –

+1

@tomredfern J'ai ajouté le code de la méthode que je veux tester. Peut-être avez-vous une meilleure solution pour tester cela? –

Répondre

3

Remarque: Je ne suis pas sûr de comprendre ce que vous essayez de faire. Qu'essayez-vous de tester exactement? Dans votre test, vous configurez service.GetLogicalDevices() pour retourner quelque chose, puis vous appelez service.GetLogicalDevices() et affirmez ce qu'il renvoie (qui, à moins que FakeItEasy ne soit cassé, devrait être ce que vous l'avez configuré pour retourner). Donc, vous n'êtes pas en train de tester le service ... vous testez le cadre moqueur! Les frameworks de simulation comme FakeItEasy sont utiles pour se moquer des dépendances du système testé (SUT), pas du SUT lui-même. Dans votre cas, si le SUT est RestService, vous devez mocker les dépendances de RestService, pas RestService lui-même. Par exemple, vous pouvez injecter un HttpClient avec un HttpMessageHandler que vous contrôlez (voir here pour plus de détails).


Maintenant, pour répondre à votre question réelle (en supposant qu'il est vraiment RestService que vous voulez faux):

Quand je lance ce code, je reçois une erreur dans TestGetLogicalDevices(). CallTo() a échoué car le service n'est pas un faux objet.

A.CallTo ne fonctionne que sur les contrefaçons; FakeItEasy ne peut pas contrôler le comportement des objets qu'il n'a pas créés.

Lorsque je tente de créer un objet factice (code commenté), il donne une erreur car RestService est un singleton avec constructeur privé

RestService est une classe, et FakeItEasy peut créer un faux pour un class, mais il le fait en héritant de la classe, il a donc besoin d'un constructeur accessible. De plus, gardez à l'esprit que seules les méthodes virtuelles peuvent être configurées. GetLogicalDevices n'est pas virtuel, donc le faux ne peut pas remplacer son comportement.

Vous avez deux options principales pour truquer RestService:

  • font le constructeur protected plutôt que private, et faire les méthodes virtuelles afin qu'ils puissent être surchargés
  • créer une interface IRestService qui représente le « public contrat "de la classe RestService, et fausse cette interface au lieu de la classe.
+1

En fait, j'essayais de tester la méthode GetLogicalDevices() mais je ne sais pas par où commencer. Je pensais que les contrefaçons me donneraient la possibilité d'obtenir des données de réponse sans faire l'appel api. Peut-être pourriez-vous me donner un exemple? @ThomasLevesque –

+1

@JorisMeylaers si vous testez 'GetLogicalDevices()', vous ne devez pas le mocker, il doit être le vrai. Ce dont vous avez besoin de se moquer, ce sont les dépendances. Dans ce cas, c'est le 'HttpClient', qui ne peut pas être moqué directement, mais vous pouvez simuler le' HttpMessageHandler' qui est utilisé par le 'HttpClient'. L'article que j'ai pointé montre un exemple de cela. Je vais essayer d'afficher un exemple plus précis. –

+1

@JorisMeylaers, voici un exemple complet pour votre cas: https://gist.github.com/thomaslevesque/622f8a0118ee1f2d46d723db2a976985. Notez que vous ne pouvez pas garder RestService comme un singleton réel, car le constructeur doit être public, mais de toute façon vous ne devriez probablement pas; singleton est un modèle terrible quand il s'agit de tests unitaires. Vous devriez utiliser l'injection de dépendance à la place. –