2017-07-11 1 views
0

Laissez-moi vous expliquer le scénario du problème. Ma tâche est de modifier la fonction compliquée testFunc() qui ressemble à ci-dessous.Activer le test unitaire d'une méthode en le rendant protégé

public String testFunc() { 
    String a = func1(); 
    String b = func2(a); 
    String c = func3(b); 
    return c; 
} 
private String func1(){ 
    return "hello"; 
} 
private String func2(String p1){ 
    return "a" + p1; 
} 
private String func3(String p1){ 
    return "b" + p1; 
} 

Je modifie la méthode testFunc et inclue ma logique. Mais étant un bon développeur, je souhaite écrire des tests pour la logique supplémentaire que j'ai écrite. Mais je n'ai ni le temps ni la patience de tester toute la méthode. Je souhaite tester uniquement la logique que j'ai ajoutée.

public String testFunc() { 
    String a = func1(); 
    String b = func2(a); 
    String c = func3(b); 
    String d = func4(c) 
    return d; 
    } 
protected final String func4(String p1) { 
    return "1" + p1; 
    } 

Est-il logique pour moi de faire la méthode FUNC4 comme définitive protégée de sorte que je puisse tester l'unité la logique à fond. Ou est-ce une mauvaise pratique de codage?

+0

Pour l'anecdote: j'aurais donné une fusion des réponses de assylias et luciano. Se tourner vers la réflexion pour le test unitaire ne demande que des ennuis. Cela rend vos tests unitaires plus lents, et cela signifie que vos tests unitaires s'arrêtent dès que vous commencez à refactoriser et que vous changez de nom. Si vous voulez vraiment tester cette méthode par elle-même, faites-la protéger * ou * déplacez la fonctionnalité dans sa propre classe et testez-la séparément. – GhostCat

Répondre

0

La modification de la visibilité d'une méthode pour les tests unitaires n'est pas une bonne pratique. Si vous utilisez Spring dans votre projet, vous pouvez utiliser ReflectionTestUtilsorg.springframework.test.util.ReflectionTestUtils (réflexions simplifiées) pour accéder aux méthodes privées et à la propriété.

Si vous ne voulez pas utiliser Spring, vous devez opter pour des réflexions Java.

+0

J'utilise le printemps et je pense que c'est une approche propre. Merci. :) –

+1

Comment cela pourrait être une approche propre? Le fait de tester vos API privées/protégées rend votre test fragile et difficile à déboguer, je doute qu'il soit facile pour quelqu'un de comprendre un an plus tard pourquoi le test échoue en raison d'un petit changement de méthode privée, surtout si vous le faites w/réflexion, par exemple le simple fait de refactoriser le nom pourrait le freiner facilement. –

+0

Vous avez raison.Je pense que je devrais reformuler mon commentaire, c'est plus propre que d'avoir la méthode protégée! –

2

Je voudrais rendre le paquet privé, ce qui est plus restrictif que protégé. Si vous utilisez déjà goyave dans votre projet, vous pouvez même annoter la méthode avec @VisibleForTesting pour rendre votre intention claire:

@VisibleForTesting final String func4(String p1) { 
    //... 
} 

En fin de compte, une méthode privée de l'emballage ne soit pas exposé au monde extérieur et ne fait pas partie de votre API, de sorte qu'il ne casse pas l'encapsulation.

+0

Pour le compte rendu: Je pense que cela devrait être la réponse acceptée, ou peut-être celle de Luciano. – GhostCat

2

Ceci est une mauvaise pratique. Les méthodes privées/protégées doivent être testables via la méthode publique qui les appelle. En modifiant le modificateur d'accès à package-private, vous exposez essentiellement les détails d'implémentation à d'autres classes, ce qui réduit l'encapsulation.

Si cela s'avère difficile, vous devriez envisager de repenser l'API publique.

+0

Dans un monde idéal, oui - mais parfois une classe a une méthode publique qui fait beaucoup sous le capot et le tester dans son ensemble est beaucoup plus compliqué que de tester les différentes étapes qui ont été déléguées à une méthode privée. – assylias

+0

@assylias exactement mon point. Je suis également conscient que c'est une mauvaise pratique. Tester la méthode publique entière dans mon scénario est compliqué et je pense qu'il est beaucoup plus propre juste pour tester ma nouvelle logique. –

+0

Pour le dossier: Je pense que ceci devrait être la réponse acceptée, ou peut-être celle d'assylias. – GhostCat

0

Eh bien, je commencerais que deux phrases dans la question est un peu contradictionary pour moi:

  1. Mais être un bon développeur, je veux écrire des tests unitaires pour la logique supplémentaire que j'ai écrit .

Et

  1. Mais je n'ai pas le temps ni la patience de tester toute la méthode. I souhaite tester uniquement la logique que j'ai ajoutée.

Soit vous un bon développeur et bien faire les choses de haut en bas, ou ne pas la patience et rien ne peut vraiment vous aider.

Pour répondre à votre question, exposer une méthode privée qui ne peut pas être réutilisé très mauvaise pratique et donc pas un bon moyen d'approche.Alors que la modification apportée ne peut pas laisser hors du contexte de la classe vous avez fait ce changement pour, par exemple, vous aviez:

class MyClass { 
    public String testFunc() { 
     String a = func1(); 
     String b = func2(a); 
     String c = func3(b); 
     return c; 
    } 
    private String func1(){ 
     return "hello"; 
    } 
    private String func2(String p1){ 
     return "a" + p1; 
    } 
    private String func3(String p1){ 
     return "b" + p1; 
    } 
} 

il donc quelques façons possibles pour vous d'étendre cette logique avec votre nouvelle fonctionnalité, par exemple, vous souhaitez decorate classe initiale avec un nouveau et l'ajout de nouvelles fonctions en elle, par exemple:

class MyNewClass extends MyClass{ 

    private MyClass delegate; 

    public MyNewClass(MyClass delegate) { 
     this.delegate = delegate; 
    } 

    public String testFunc() { 
     String c = delegate.testFunc(); 
     return func4(c); 
    } 

    private final String func4(String p1) { 
     return "1" + p1; 
    } 
} 

maintenant, vous pouvez écrire votre test unitaire par mockingMyClass instance et vérifier que la logique n'ajouté récemment.

Une autre alternative possible sera d'extraire de nouvelles fonctionnalités dans sa propre classe et d'écrire un test uniquement pour cela.