Bon exemple de conception orientée objet en Java


J'ai une classe Java appelée TestExecutor qui est responsable de starting un test. Le test comporte un certain nombre d'étapes:

- Update test repository
- Locate the test script
- Create result empty directory
- Execute command
- Parse output
- Update database

Pour chacune de ces étapes, j'ai créé des méthodes privées dans la classe TestExecutor qui effectuent chacune des actions ci-dessus, le tout entouré d'un bloc try-catch. Je suis conscient que ce n'est pas une bonne conception car ma classe en fait trop et est également pénible à tester en raison d'une grande quantité de fonctionnalités cachées dans des méthodes privées.

J'aimerais pour entendre vos suggestions pour refactoriser cette classe car je ne sais pas comment m'éloigner de quelque chose de similaire à la structure ci-dessus. Exemple de code ci-dessous:

public void start() throws TestExecuteException {
    try {
        updateRepository();
        locateScript();
        createResultDirectory();
        executeCommand();
        parseOutput();
        updateDatabase();
    catch(a,b,c) {
    }
}

private updateRepository() {
    // Code here
}
// And repeat for other functions
Author: Adam, 2017-01-24

3 answers

Eh bien, votre classe me semble ok.

Je suis conscient que ce n'est pas une bonne conception car ma classe en fait trop

Dans la mesure où la classe a une seule responsabilité, le nombre de méthodes n'a pas d'importance.

Cochez cette case modèle de conception de méthode de modèle . Votre classe fait quelque chose de similaire à ce que fait la classe abstract Game.

public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();

   //template method
   public final void play(){

      //initialize the game
      initialize();

      //start game
      startPlay();

      //end game
      endPlay();
   }
}

Et est aussi une douleur à l'unité de test en raison d'une grande quantité de fonctionnalités être caché en privé méthodes

Lire ceci & ceci sur le test de méthodes privées. Vous pouvez également utiliser un framework comme PowerMock qui vous aide à tester du code non testable.

 0
Author: underdog, 2017-05-23 11:54:13

J'aimerais entendre vos suggestions pour refactoriser cette classe car je ne sais pas comment m'éloigner de quelque chose de similaire à la structure ci-dessus

Vous devriez certainement jeter un œil aux principes SOLID comme point de départ pour écrire du code orienté objet propre et testable. J'ai été initié au début de ma carrière et cela aide vraiment beaucoup de suivre ces principes.

Cela dit, je commencerais par regrouper les fonctionnalités associées en les différentes classes. Par exemple, updateRepository() et updateDatabase() peuvent être déplacés vers une classe distincte appelée DatabaseHelper. De même, locateScript() et createResultDirectory() semblent être des opérations liées au disque et peuvent être déplacées vers une classe distincte appelée DirectoryHelper. Je crois que vous obtenez l'essentiel de lui. Ce que vous venez de réaliser, c'est La Séparation des préoccupations.

Maintenant que vous avez des classes séparées, vous devez les rassembler et les mettre au travail. Votre TestExecutor peut continuer à avoir le methods que vous avez listé. Le seul différent sera que ces méthodes vont maintenant déléguer leur travail aux classes individuelles que nous avons créées ci-dessus. Pour cela, TestExecutor aura besoin d'une référence aux classes DatabaseHelper et DirectoryHelper. Vous pouvez simplement instancier ces classes directement dans TestExecutor. Mais cela signifierait que TestExecutor est étroitement couplé à une implémentation. Ce que vous pouvez faire à la place, c'est demander au code en dehors de TestExecutor de fournir les DatabaseHelpe et DirectoryHelper à utiliser. Ceci est connu comme Inversion de Dépendance par Injection de Dépendance. Avantage de cette approche, vous pouvez maintenant passer n'importe quelle sous-classe de DatabaseHelper et DirectoryHelper à TaskExecutor et il n'a pas besoin de connaître les détails de l'implémentation. Cela facilite le test unitaire de TaskExecutor en se moquant de ces dépendances au lieu de passer des instances réelles.

Je vous laisserai le reste des SOLID principes à explorer, à mettre en œuvre et à apprécier.

 0
Author: CKing, 2017-02-05 14:14:35

Je ferais de cette façon. Tout d'abord, appliquer le contrat que chaque étape de test devrait avoir.

interface TestCommand{
  void run();
}

Faites maintenant vos commandes de test en tant que classes séparées. Essayez de rendre ces classes de commandes génériques afin de les réutiliser pour des types de commandes similaires. Maintenant, dans votre classe où vous souhaitez exécuter un test, configurez les étapes de test comme suit.

//in your test class do this.
List<TestStep> testCommands = new ArrayList<>();
testCommands.add(new UpdateRepoCommand());
testCommands.add(new LocateScriptCommand());
// and so on....

Maintenant, exécutez toutes vos étapes chronologiquement.

public void start(testSteps) throws TestExecuteException {
    try {
        for(TestCommand command : testCommands){
           command.run()
    }        
    catch(Exception e) {
      //deal with e
    }
}

De plus, comme CKing décrit ci-dessus, suivre le principe SOLIDE à l'intérieur de ces tests étape. Injectez des dépendances et écrivez le test unitaire pour elles séparément.

 0
Author: sam33r, 2017-02-05 14:30:35