Comment tester une fonction privée dans angular 2?
class FooBar {
private _status: number;
constructor( private foo : Bar ) {
this.initFooBar();
}
private initFooBar(){
this.foo.bar( "data" );
this._status = this.fooo.foo();
}
public get status(){
return this._status;
}
}
La solution que j'ai trouvée
Placez le code de test lui-même dans la fermeture ou ajoutez du code dans la fermeture qui stocke les références aux variables locales sur les objets existants dans la portée externe.
Supprimez ultérieurement le code de test à l'aide d'un outil. http://philipwalton.com/articles/how-to-unit-test-private-functions-in-javascript/
Veuillez me suggérer une meilleure façon de résoudre ce problème si vous en avez fait?
PS
La plupart des réponses à un type de question similaire comme celle-ci ne donnent pas de solution au problème, c'est pourquoi je pose cette question
La plupart des développeurs disent que vous ne testez pas les fonctions privées, mais je ne dis pas qu'elles sont fausses ou correctes, mais il est nécessaire que mon cas teste privé.
Réponses:
Je suis avec vous, même si c'est un bon objectif de "tester uniquement l'API publique", il y a des moments où cela ne semble pas aussi simple et vous sentez que vous choisissez entre compromettre l'API ou les tests unitaires. Vous le savez déjà, puisque c'est exactement ce que vous demandez de faire, donc je ne vais pas y entrer. :)
Dans TypeScript, j'ai découvert plusieurs façons d'accéder à des membres privés à des fins de test unitaire. Considérez cette classe:
Même si l'accès des TS aux membres de la classe en utilisant
private
,protected
,public
le JS compilé n'a pas de membres privés, puisque ce n'est pas une chose à JS. Il est uniquement utilisé pour le compilateur TS. À cet effet:Vous pouvez affirmer
any
et empêcher le compilateur de vous avertir des restrictions d'accès:Le problème avec cette approche est que le compilateur n'a tout simplement aucune idée de ce que vous faites à droite du
any
, donc vous n'obtenez pas les erreurs de type souhaitées:Cela rendra évidemment le refactoring plus difficile.
Vous pouvez utiliser array access (
[]
) pour accéder aux membres privés:Bien que cela ait l'air génial, TSC validera en fait les types comme si vous y aviez accédé directement:
Pour être honnête, je ne sais pas pourquoi cela fonctionne.Il s'agit apparemment d'une "trappe d'évacuation" intentionnelle pour vous donner accès aux membres privés sans perdre la sécurité du type. C'est exactement ce que je pense que vous voulez pour vos tests unitaires.Voici un exemple de travail dans le TypeScript Playground .
Modifier pour TypeScript 2.6
Une autre option que certains aiment est d'utiliser
// @ts-ignore
( ajoutée dans TS 2.6 ) qui supprime simplement toutes les erreurs sur la ligne suivante:Le problème avec ceci est que cela supprime toutes les erreurs sur la ligne suivante:
Personnellement, je considère
@ts-ignore
une odeur de code, et comme le disent les documents:la source
as any
: vous perdez toute vérification de type.Vous pouvez appeler des méthodes privées . Si vous avez rencontré l'erreur suivante:
utilisez simplement
// @ts-ignore
:la source
as any
dans la mesure où vous perdez toute vérification de type, en fait vous perdez toute vérification de type sur toute la ligne.Comme la plupart des développeurs ne recommandent pas de tester la fonction privée , pourquoi ne pas la tester?.
Par exemple.
YourClass.ts
TestYourClass.spec.ts
Merci à @Aaron, @Thierry Templier.
la source
N'écrivez pas de tests pour les méthodes privées. Cela va à l'encontre de l'intérêt des tests unitaires.
Exemple
Le test de cette méthode ne devrait pas avoir besoin de changer si ultérieurement l'implémentation change mais que l'
behaviour
API publique reste la même.Ne rendez pas les méthodes et les propriétés publiques uniquement pour les tester. Cela signifie généralement que:
la source
Le but de "ne pas tester les méthodes privées" est vraiment de tester la classe comme quelqu'un qui l'utilise .
Si vous avez une API publique avec 5 méthodes, n'importe quel consommateur de votre classe peut les utiliser et vous devez donc les tester. Un consommateur ne doit pas accéder aux méthodes / propriétés privées de votre classe, ce qui signifie que vous pouvez modifier les membres privés lorsque la fonctionnalité exposée publique reste la même.
Si vous comptez sur une fonctionnalité extensible interne, utilisez à la
protected
place deprivate
.Notez qu'il
protected
s'agit toujours d'une API publique (!) , Juste utilisée différemment.Test unitaire des propriétés protégées de la même manière qu'un consommateur les utiliserait, via le sous-classement:
la source
Cela a fonctionné pour moi:
Au lieu de:
Ce:
la source
Désolé pour le nécro sur ce post, mais je me sens obligé de peser sur deux choses qui ne semblent pas avoir été abordées.
Tout d'abord - lorsque nous avons besoin d'accéder à des membres privés sur une classe pendant les tests unitaires, c'est généralement un gros drapeau rouge que nous avons gaffé dans notre approche stratégique ou tactique et avons violé par inadvertance le principe de responsabilité unique en poussant comportement là où il n’appartient pas. Ressentir le besoin d'accéder à des méthodes qui ne sont en réalité rien de plus qu'un sous-programme isolé d'une procédure de construction est l'une des occurrences les plus courantes de ceci; cependant, c'est un peu comme si votre patron s'attend à ce que vous vous présentiez au travail prêt à partir et qu'il ait aussi un besoin pervers de savoir quelle routine matinale vous avez traversée pour vous mettre dans cet état ...
L'autre exemple le plus courant de ce phénomène est celui où vous vous trouvez en train d'essayer de tester la proverbiale «classe de Dieu». C'est un type particulier de problème en soi, mais il souffre du même problème de base avec le besoin de connaître les détails intimes d'une procédure - mais cela sort du sujet.
Dans cet exemple spécifique, nous avons effectivement attribué la responsabilité d'initialiser complètement l'objet Bar au constructeur de la classe FooBar. Dans la programmation orientée objet, l'un des principaux tenants est que le constructeur est "sacré" et doit être protégé contre les données invalides qui invalideraient son propre état interne et le laisseraient prêt à échouer ailleurs en aval (dans ce qui pourrait être un pipeline.)
Nous n'avons pas réussi à le faire ici en permettant à l'objet FooBar d'accepter une barre qui n'est pas prête au moment où la FooBar est construite, et avons compensé en "piratant" l'objet FooBar pour prendre les choses en soi mains.
Ceci est le résultat d'un échec d'adhérer à un autre tenent de la programmation orientée objet (dans le cas de Bar,) qui est que l'état d'un objet doit être entièrement initialisé et prêt à gérer tous les appels entrants à ses `` membres publics '' immédiatement après sa création. Maintenant, cela ne signifie pas immédiatement après l'appel du constructeur dans toutes les instances. Lorsque vous avez un objet qui a de nombreux scénarios de construction complexes, il est préférable d'exposer les setters à ses membres facultatifs à un objet qui est implémenté conformément à un modèle de conception de création (Factory, Builder, etc ...) dans l'un des ces derniers cas,
Dans votre exemple, la propriété "status" de la barre ne semble pas être dans un état valide dans lequel un FooBar peut l'accepter - donc le FooBar fait quelque chose pour corriger ce problème.
Le deuxième problème que je vois est qu'il semble que vous essayez de tester votre code plutôt que de pratiquer le développement piloté par les tests. C'est certainement ma propre opinion en ce moment; mais, ce type de test est vraiment un anti-pattern. Ce que vous finissez par faire, c'est tomber dans le piège de vous rendre compte que vous avez des problèmes de conception fondamentaux qui empêchent votre code d'être testable après coup, plutôt que d'écrire les tests dont vous avez besoin et de programmer ensuite les tests. Quoi qu'il en soit, vous rencontrez le problème, vous devriez toujours vous retrouver avec le même nombre de tests et de lignes de code si vous aviez vraiment réalisé une implémentation SOLID. Alors, pourquoi essayer de faire de l'ingénierie inverse dans un code testable alors que vous pouvez simplement résoudre le problème au début de vos efforts de développement?
Si vous aviez fait cela, alors vous auriez réalisé bien plus tôt que vous alliez devoir écrire du code plutôt dégoûtant afin de le tester par rapport à votre conception et que vous auriez eu l'opportunité dès le début de réaligner votre approche en déplaçant le comportement vers des implémentations qui sont facilement testables.
la source
Je suis d'accord avec @toskv: je ne recommanderais pas de faire ça :-)
Mais si vous voulez vraiment tester votre méthode privée, vous pouvez être conscient que le code correspondant pour le TypeScript correspond à une méthode du prototype de la fonction constructeur. Cela signifie qu'il peut être utilisé à l'exécution (alors que vous aurez probablement des erreurs de compilation).
Par exemple:
sera transpilé en:
Voir ce plunkr: https://plnkr.co/edit/calJCF?p=preview .
la source
Comme beaucoup l'ont déjà dit, même si vous souhaitez tester les méthodes privées, vous ne devez pas pirater votre code ou votre transpilateur pour le faire fonctionner pour vous. TypeScript moderne refusera la plupart des hacks que les gens ont fournis jusqu'à présent.
Solution
TLDR ; si une méthode doit être testée, vous devez découpler le code en une classe que vous pouvez exposer à la méthode publique pour être testée.
La raison pour laquelle vous avez la méthode privée est que la fonctionnalité n'appartient pas nécessairement à être exposée par cette classe, et donc si la fonctionnalité n'y appartient pas, elle doit être découplée dans sa propre classe.
Exemple
J'ai parcouru cet article qui explique très bien comment vous devez vous attaquer aux tests de méthodes privées. Il couvre même certaines des méthodes ici et explique pourquoi elles sont de mauvaises implémentations.
https://patrickdesjardins.com/blog/how-to-unit-test-private-method-in-typescript-part-2
Remarque : ce code est extrait du blog lié ci-dessus (je duplique au cas où le contenu derrière le lien changerait)
Avant Aprèsla source
appeler une méthode privée en utilisant des crochets
Fichier TS
fichier spect.ts
la source
La réponse d' Aaron est la meilleure et fonctionne pour moi :) Je voterais mais malheureusement je ne peux pas (réputation manquante).
Je dois dire que tester des méthodes privées est le seul moyen de les utiliser et d'avoir un code propre de l'autre côté.
Par exemple:
Il est très logique de ne pas tester toutes ces méthodes à la fois, car nous aurions besoin de nous moquer de ces méthodes privées, ce que nous ne pouvons pas simuler parce que nous ne pouvons pas y accéder. Cela signifie que nous avons besoin de beaucoup de configuration pour un test unitaire pour tester cela dans son ensemble.
Ceci dit, le meilleur moyen de tester la méthode ci-dessus avec toutes les dépendances est un test de bout en bout, car ici un test d'intégration est nécessaire, mais le test E2E ne vous aidera pas si vous pratiquez TDD (Test Driven Development), mais testez toute méthode le fera.
la source
Cette route que je prends est celle où je crée des fonctions en dehors de la classe et assigne la fonction à ma méthode privée.
Maintenant, je ne sais pas quel type de règles OOP je suis en train de briser, mais pour répondre à la question, voici comment je teste les méthodes privées. Je souhaite à quiconque de vous conseiller sur les avantages et les inconvénients de cela.
la source