Ilproblema:
Vogliotestare una classe che crea unanuovaistanza di una classe My_Notice definita al difuori delplugin (chiamiamola "Main Plugin").
Ilmio unittestnon sanulla di My_Notice perché è definitoin una libreria diterzeparti (un altroplugin,per laprecisione).
Pertanto,ho queste opzioni (per quantone so):
Stub la classe My_Notice : difficile damantenere
Includii filenecessari dalla libreria diterzeparti:potrebbefunzionare,ma sto rendendoi mieitestmenoisolati
Stub dinamicamente la classe:non sono sicuro che siapossibile,ma sarebbemolto simile a deridere una classe,tranneperilfatto che dovrebbe anche creare la definizione della stessa,quindi la classe che stotestando saràin grado diistanziareit.
La risposta di @gmazzap sottolinea che dovremmoevitare di creare questo sorta di dipendenze che è qualcosa che sonototalmente d'accordo.
E l'idea di creare classi stubnonmi sembrabuona:preferiscoincludereil codice del "Main Plugin",contutte le conseguenze.
Tuttavianon vedo comepossofare altrimenti.
Ecco unesempio del codice che sto cercando ditestare:
Fondamentalmente,questa classe ha unmetodo che verrà agganciato a enabled_plugin . Questometodo crea un'istanza di una classe di "notifica",che verrà archiviata da qualcheparte dall'istanza My_Notices passata al costruttore.
Il costruttore della classe My_Notice riceve due argomenti dibase (un UIDe un "gruppo")e ottiene alcuneproprietàimpostate (ricorda che lo stessoproblema è con My_Admin_Notice_Action classe).
Comepotrei rendere la classe My_Notice una dipendenzainiettata?
Ovviamente,potrei usare un array associativo,chiamare un'azione,che è agganciato dal "Main Plugin"e chetraduce quell'arraynegli argomenti della classe,manonmi sembrapulito.
The issue:
I want to test a class which creates a new instance of a My_Notice class defined outside the plugin (let's call it the "Main Plugin").
My unit test knows nothing about My_Notice because it's defined in a third party library (another plugin, to be precise).
Therefore, I have these options (as far as I know):
Stub the My_Notice class: hard to maintain
Include the needed files from the third party library: this may work, but I'm making my tests less isolated
Dynamically stub the class: not sure if that's even possible, but it would be very similar to mocking a class, except that it should also create the definition of the same, so the class I'm testing will be able to instantiate it.
The answer from @gmazzap points out that we should avoid creating this sort of dependencies which is something I totally agree.
And the idea of creating stub classes doesn't seem good to me: I'd rather include the code of the "Main Plugin", with all the consequences).
However I don't see how can I do otherwise.
Here's an example of the code I'm trying to test:
class My_Admin_Notices_Handler {
public function __construct( My_Notices $admin_notices ) {
$this->admin_notices = $admin_notices;
}
/**
* This will be hooked to the `activated_plugin` action
*
* @param string $plugin
* @param bool $network_wide
*/
public function activated_plugin( $plugin, $network_wide ) {
$this->add_notice( 'plugin', 'activated', $plugin );
}
/**
* @param string $type
* @param string $action
* @param string $plugin
*/
private function add_notice( $type, $action, $plugin ) {
$message = '';
if ( 'activated' === $action ) {
if ( 'plugin' === $type ) {
$message = __( '%1s Some message for plugin(s)', 'my-test-domain' );
}
if ( 'theme' === $type ) {
$message = __( '%1s Some message for the theme', 'my-test-domain' );
}
}
if ( 'updated' === $action && ( 'plugin' === $type || 'theme' === $type ) ) {
$message = __( '%1s Another message for updated theme or plugin(s)', 'my-test-domain' );
}
if ( $message ) {
$notice = new My_Notice( $plugin, 'wpml-st-string-scan' );
$notice->text = $message;
$notice->actions = array(
new My_Admin_Notice_Action( __( 'Scan now', 'my-test-domain' ), '#' ),
new My_Admin_Notice_Action( __( 'Skip', 'my-test-domain' ), '#', true ),
);
$this->admin_notices->add_notice( $notice );
}
}
}
Basically, this class has a method which will be hooked to activated_plugin. This method builds an instance of a "notification" class, which will be stored somewhere by the My_Notices instance passed to the constructor.
The constructor of the My_Notice class receives two basic arguments (a UID and a "group") and gets some properties set (mind that the same issue is with the My_Admin_Notice_Action class).
How could I make the My_Notice class an injected dependency?
Of course, I could use an associative array, call some action, which is hooked by the "Main Plugin" and which translates that array in the class's arguments, but it doesn't look clean to me.
Ilproblema èprobabilmenteilmodoin cui hai strutturatoiltuo codicee non comeimplementare l'approccio A o B,ma le domandegeneriche di unittest come questa sonoprobabilmentemeglioposte a SO.Francamentenon vedo alcunproblema coniltest del codice,quindinon riesconemmeno a capire qual èilproblema che stai affrontando.Aproposito,soloperché una risposta ha ottenuto 30 votipositivinon significa che sia l'unicomodo validoperfare le cose
The problem is probably the way you structured your code, and not with how to implement approach A or B, but generic unit testing questions like this are probably better asked at SO. I frankly don't see any problem with testing your code so can't even understand what is the issue you are facing. BTW just because an answer got 30 upvotes doesn't mean that it is the only valid way to do things
@ MarkKaplun Ho aggiunto alcuni chiarimenti su qual èilproblema coniltest di questa classe.Spero che questo abbiapiù senso.Ho aggiunto la domanda qui,in seguito a quella originale,che sitrovanella stessa rete.Poichéilproblema èmolto simile a quellopostonella domanda originale,non sono sicuro al 100% di doverlo spostarein SO,ma qualsiasiguida èmoltogradita!
@MarkKaplun I added some clarification about what is the issue with testing this class. I hope this makes more sense. I added the question here, as a follow up of the original one, which is in the same network. Since the issue is very similar to the one posed in the original question, I'm not 100% sure I must move it at SO, but any guidance is very welcome!
Quelloera unperiodo diversoin cui le regole quierano diversee la rispostanon è statabuona.Sebbene ogniparola sia verae io sono d'accordo conessa,ilpunto centrale di scrivere unpluginper wordpress èintegrarlo conesso,quinditestareisolatamenteti dàmoltopoco,specialmente seiltuo codice come quello chemostri qui è relativamentebanale.Testareisolatamente è ottimo,ma ancheiltest dovrebbeessere utilee non solopuro.
That was different time in which the rules here were different, and the answer is just not a good one. While every word there is true and I agree with it, the whole point of wrting a plugin for wordpress is integrating with it, so testing in isolation gives you very little especially if your code as in the one you show here is relatively trivial. Testing in isolation is great, but testing should also be useful and not just pure.
Questopotrebbeessere visto come un corollario del Testing hooks callback .
Ilproblema: Vogliotestare una classe che crea unanuovaistanza di una classe
My_Notice
definita al difuori delplugin (chiamiamola "Main Plugin").Ilmio unittestnon sanulla di
My_Notice
perché è definitoin una libreria diterzeparti (un altroplugin,per laprecisione). Pertanto,ho queste opzioni (per quantone so):My_Notice
: difficile damantenereLa risposta di @gmazzap sottolinea che dovremmoevitare di creare questo sorta di dipendenze che è qualcosa che sonototalmente d'accordo. E l'idea di creare classi stubnonmi sembrabuona:preferiscoincludereil codice del "Main Plugin",contutte le conseguenze.
Tuttavianon vedo comepossofare altrimenti.
Ecco unesempio del codice che sto cercando ditestare:
Fondamentalmente,questa classe ha unmetodo che verrà agganciato a
enabled_plugin
. Questometodo crea un'istanza di una classe di "notifica",che verrà archiviata da qualcheparte dall'istanzaMy_Notices
passata al costruttore.Il costruttore della classe
My_Notice
riceve due argomenti dibase (un UIDe un "gruppo")e ottiene alcuneproprietàimpostate (ricorda che lo stessoproblema è conMy_Admin_Notice_Action
classe).Comepotrei rendere la classe
My_Notice
una dipendenzainiettata?Ovviamente,potrei usare un array associativo,chiamare un'azione,che è agganciato dal "Main Plugin"e chetraduce quell'arraynegli argomenti della classe,manonmi sembrapulito.