Comment savoir si une méthode java peut être appelée dans une autre méthode


J'essaie d'écrire un test pour mon projet qui me permet de savoir, je suppose par réflexion, si les classes que je teste peuvent appeler une méthode spécifique.

Notez l'exemple de code ci-dessous:

class A implements SomeInterface {
    @Override
    public process(B bInstance) {
        if (Math.rand() < 0.5)
            bInstance.thirdPartyCall(param1, param2); //I need this!
    }
}

La ou les classes remplacent un processus de méthode (...) qui pourrait appeler une méthode à partir de l'un des objets passés dans process (). J'ai besoin de mon test pour savoir si la ou les classes en question ont été codées pour inclure des appels à B(), et quels sont les paramètres. Si nous pouvons seulement obtenir le invocation en tant que chaîne, j'espère pouvoir travailler avec cela.

Nous avons tout le code source pour les classes qui remplacent A() et la classe qui contient B(), mais nous avons besoin que cela soit dynamique pour des raisons de maintenance future. Puisque nous avons besoin que cela soit dynamique, je ne peux pas simplement créer une maquette car je ne saurai pas si les paramètres de ma maquette vont frapper le code qui appelle les méthodes de bInstance.

Author: jeff, 2012-08-07

1 answers

Vous ne seriez pas en mesure de le faire via la réflexion, car la réflexion d'une manière générale peut vous parler de la signature des classes, mais ne vous donne rien sur leurs implémentations.

Pour faire ce que vous recherchez, vous devez parcourir le bytecode et regarder les codes invokevirtual (ou invokestatic pour les méthodes statiques) qui apparaissent dans chaque définition de méthode. En utilisant cela, vous pouvez construire une sorte de dictionnaire qui détermine ce qui appelle quoi. (Vraisemblablement c'est quoi LesEs s'appuient sur la fonctionnalité" rechercher des usages".)

Pour les méthodes "autonomes" que vous avez définies vous-même, cela pourrait être suffisant. Cependant, les choses deviendront plus délicates pour les méthodes qui remplacent ou implémentent des méthodes définies ailleurs - donc si vous définissez votre propre Runnable, ou Map sous-classe par exemple. Il n'est pas facilement possible (peut-être même prouvé impossible) de savoir quelle sera l'implémentation concrète d'un appel de méthode simplement en inspectant le bytecode, vous ne pouvez donc pas dire avec certitude si votre map get() est appelé, si l'appelant avait tout simplement une référence à Map. De même, si vous avez une implémentation Runnable, il est peu probable que votre classe A appelle directement run; cet appel proviendra probablement de quelque part dans la bibliothèque standard (par exemple dans un ExecutorService ou à partir de Thread.start()), vous devrez donc créer une très grande carte d'appels transitifs sur tout le chemin de classe, pas seulement votre propre code.

Plus bien sûr, pour le ramener à votre point initial - vous ne seriez pas capable de détecter les appels réfléchissants du tout. Method.invoke() peut appeler à peu près n'importe quoi du point de vue de l'analyse statique.


Je pense que votre intention est bonne, mais à moins que vous ne puissiez trouver une bibliothèque existante à utiliser, cela ne vaudra pas la peine de développer ce type de métrique de "couverture" pour vos tests.

 2
Author: Andrzej Doyle, 2012-08-14 10:27:39