Modelli sorgente di unit testing


10

Ho diversi modelli nella mia estensione personalizzata che servono solo allo scopo compilando alcune selezioni e / o selezioni multiple nel modulo Aggiungi / Modifica delle mie entità.
Quindi sono quelli che magento chiama "modelli di origine".
I valori coinvolti sono sempre gli stessi e i metodi restituiscono la stessa cosa.
Come devo testarli? O meglio, dovrei scrivere test unitari per loro?
Ecco un esempio
La seguente classe viene utilizzata per aggiungere / modificare il modulo per un campo chiamato typee per la colonna della griglia dello stesso campo.

<?php
namespace Sample\News\Model\Author\Source;

use Magento\Framework\Option\ArrayInterface;

class Type implements ArrayInterface
{
    const COLLABORATOR = 1;
    const EMPLOYEE = 2;

    /**
     * Get options
     *
     * @return array
     */
    public function toOptionArray()
    {
        $_options = [
            [
                'value' => '',
                'label' => ''
            ],
            [
                'value' => self::COLLABORATOR,
                'label' => __('Collaborator')
            ],
            [
                'value' => self::EMPLOYEE,
                'label' => __('Employee')
            ],
        ];
        return $_options;
    }

    /**
     * get options as key value pair
     *
     * @return array
     */
    public function getOptions()
    {
        $_tmpOptions = $this->toOptionArray();
        $_options = [];
        foreach ($_tmpOptions as $option) {
            $_options[$option['value']] = $option['label'];
        }
        return $_options;
    }
}

Risposte:


15

Questo è un ottimo thread e mi piacciono molto sia le risposte di @KAndy che @fschmengler.
Vorrei aggiungere alcune considerazioni aggiuntive che ritengo utili quando faccio una domanda come "Dovrei testare X?" o "Come devo testare X?".

Cosa potrebbe andare storto?

  • Potrei fare un errore di digitazione (succede sempre)
    Questo di solito non giustifica la scrittura di un test.
  • Copierò il codice di cui ho bisogno dal core o da un modulo diverso, e poi lo adeguerò alle mie esigenze?
    Trovo che in realtà questa sia una cosa molto pericolosa da fare che spesso lascia bug sottili. In questo caso, preferisco scrivere un test, se non è troppo costoso. Effettuare la configurazione dei modelli di origine in realtà li renderebbe IMO più rischiosi.
  • Può esserci un conflitto con un modulo diverso?
    Questo vale quasi solo per il codice di configurazione. In tal caso, mi piace fare un test di integrazione che mi dica quando succede.
  • Magento potrebbe cambiare l'API in una versione futura?
    Molto improbabile in questo caso, poiché il codice dipende solo da un'interfaccia. Ma sono coinvolte le classi più concrete o se il mio codice estende una classe principale, questo diventa un rischio maggiore.
  • Una nuova versione di PHP potrebbe violare il mio codice. O forse voglio supportare PHP 5.6 per gli anni a venire.
    Ancora una volta, molto improbabile qui, ma in alcuni casi voglio che un test mi avverta, in futuro dovrei cambiare il codice per usare una sintassi incompatibile.

Quanto costa testare il codice?

Questo ha due aspetti:

  • La quantità di sforzo e il tempo necessario per scrivere un test
  • La quantità di sforzo e il tempo necessario per testare il pezzo di codice che sto per scrivere manualmente.

Durante lo sviluppo di un pezzo di codice, tendo a dover eseguire il codice che sto scrivendo abbastanza spesso fino a quando lo considero fatto. Questo è ovviamente molto più semplice con un test unitario.

Nel tuo caso scrivere un test è morto a buon mercato. Non ci vuole molto tempo o fatica. @KAndy ha ragione nel ritenere che tutto il codice debba essere mantenuto, ma non tutti i test devono essere mantenuti.
Questo potrebbe essere un esempio in cui scriverei un test unitario, solo per verificare che non commetta un errore scemo, e poi lo cancellerei al termine della lezione. Se un test non fornisce un valore a lungo termine, penso che eliminarli abbia senso.

Questa domanda è importante anche in termini di scelta del tipo di test da scrivere: unità o integrazione per esempio.

Quanto è prezioso il pezzo di codice che sto scrivendo?

Se un pezzo di codice che sto scrivendo è essenziale per il servizio fornito da un modulo, lo collaudo, indipendentemente da quanto sia banale.
Se è solo un piccolo metodo di utilità, ad esempio focalizzato sull'interfaccia utente e non parte della logica aziendale, forse no.

Il codice dovrà cambiare?

Nel corso del tempo sono diventato così abituato ad avere la copertura dei test, che cambiare il codice scoperto è molto insicuro. Ciò include cose così semplici come l'aggiunta di un'opzione a un modello di origine, ma anche cose come lo spostamento di una classe in una cartella / spazio dei nomi diverso o la ridenominazione di un metodo.
Avere test in atto per tali cambiamenti è inestimabile.

Ha bisogno di documentazione?

Quanto è difficile usare il codice? Nel tuo esempio è banale, ma in alcuni casi più complessi, avere un test è ottimo per scopi di documentazione per altri sviluppatori (o me stesso in pochi mesi).

Esplorazione e apprendimento

Se sto lavorando su un codice e non sono sicuro di come testarlo, trovo molto utile scrivere un test. Il processo mi dà quasi sempre una comprensione più profonda di ciò con cui ho a che fare.
Ciò è particolarmente vero per gli sviluppatori che si considerano ancora in fase di apprendimento dei test.
Questo è anche un esempio in cui potrebbe avere senso eliminare il test in seguito, poiché il valore principale fornito era l'apprendimento.

Disciplina e stress

Attaccare al circuito rosso-verde-refactor mi aiuta ad andare veloce. Ciò è particolarmente vero sotto pressione. Quindi, anche se qualche pezzo di codice non è veramente degno del test, potrei comunque seguire TDD, specialmente se il codice è banale da testare.
Questo mi tiene al corrente e vigile.

Cosa e come testare?

Considera anche che puoi scrivere il test con una granularità molto diversa.

  • Verifica del valore restituito esatto.
    Questo sarà un test molto rigido che dovrà essere adattato ad ogni cambiamento. Desideri interrompere il test, ad esempio, se l'ordine degli articoli nell'array di ritorno cambia?
  • Verifica della struttura del valore restituito.
    Per il modello di origine questo potrebbe controllare ciascun sotto-array come due record, uno con una labele uno con una valuechiave.
  • Verifica degli strumenti di classe ArrayInterface.
  • Il test della classe fornisce getOptions()anche se quel metodo non fa parte dell'interfaccia implementata.

Per ogni possibile cosa che può essere testata, considerare valore, manutenibilità e costi.

Sommario

Per riassumere: non esiste una vera risposta singola a una domanda se un pezzo di codice debba essere testato o meno. La risposta sarà diversa per ogni sviluppatore a seconda delle circostanze.


2
Bella risposta! Voglio evidenziare la parte "Elimina i test quando non forniscono più valore" - a volte i vecchi test che hanno aiutato durante lo sviluppo iniziale, si stanno facendo strada nel lungo termine.
Fabian Schmengler,

1
hai appena risposto ad altre 2 domande di cui avevo dubbi. grazie
Marius

6

A mio avviso, non esiste una risposta generale a "scrivere test unitari per modelli sorgente, sì o no"

Ho scritto unit test per i modelli di origine, ma quelli erano modelli di origine dinamici che hanno recuperato dati esterni e lì ha perfettamente senso.

Per i modelli sorgente che non sono altro che array glorificati (come nel tuo esempio), non mi preoccuperei di scrivere test unitari. Ma in qualche modo, devi assicurarti di non aver fatto un errore. Esistono diverse opzioni:

  1. unit test
  2. test di integrazione
  3. guarda manualmente la configurazione

Stai seguendo TDD? Quindi selezionare tra (1) e (2) o entrambi. Altrimenti, selezionare tra (2) e (3).


Se si utilizzano i modelli di origine per le opzioni di configurazione del sistema, un test di integrazione (un test per tutte le opzioni di configurazione) potrebbe visualizzare la sezione di configurazione e verificare se gli <select>elementi sono presenti e contengono i valori previsti. Ricorda che non si tratta di testare una determinata classe ma di verificare che tutto sia collegato correttamente.


E come ha detto @KAndy, idealmente non avresti bisogno di così tanto boilerplate, basta estendere una classe base che è già testata dall'unità e sovrascrivere una proprietà o definire i valori nella configurazione esterna.

In quello scenario, i test unitari per implementazioni concrete non forniscono alcun valore aggiuntivo. Se hai molte di queste classi, potrebbe essere una buona idea scrivere ArraySourcetu stesso una classe base , purché Magento non la fornisca.


Con una tale classe base, il tuo modello sorgente potrebbe apparire così:

class Type extends ArraySource
{
    const COLLABORATOR = 1;
    const EMPLOYEE = 2;
    protected $elements = [
        self::COLLABORATOR => 'Collaborator',
        self::EMPLOYEE     => 'Employee',
    ];
    protected $withEmpty = true;
    protected $translate = true;
}

Grazie per la conferma. Proverò a trasformare i miei array glorificati in un elenco di opzioni configurabili, ma lo stesso vale per i modelli che avranno esattamente N opzioni? Come un modello sorgente "status".
Marius

Non vedo come un modello sorgente di "status" sarebbe diverso dal tuo esempio di "tipo di autore"
Fabian Schmengler,

perché potrei usare i valori 0 e 1 (come costanti di classe) sul frontend, per filtrare ad esempio le entità abilitate. Voglio dire in questo caso, i valori delle opzioni hanno una logica dietro di loro. non sono solo key=>valuecoppie.
Marius

Ma questa logica non fa parte del modello sorgente, giusto? Ciò significa che qui non importa. Avrai ancora le costanti da usare in altri luoghi. Ho aggiunto un esempio di come utilizzerei tale impianto.
Fabian Schmengler,

5

Come devo testarli?

Penso che non dovresti.

Aggiungi codice al sistema per aumentare i costi di supporto e manutenzione, ma il processo di test dovrebbe essere LEAN .

Più di questo codice non dovrebbe esistere. Credo che in Magento dovrebbe essere un modo dichiarativo generico per definire gruppi di opzioni da utilizzare in luoghi diversi. E la tua riluttanza a scrivere test per questa classe mi mostra l'odore del cattivo codice


1
Grazie. Quindi stai dicendo che queste opzioni non dovrebbero essere hardcoded ma provengono da un file di configurazione (di.xml per esempio). Posso farlo. Ma lo stesso vale per i modelli di origine dello stato? Voglio dire, se ho la stessa classe di cui sopra ma solo con lo stato abilitato e disabilitato (1,0) dovrei usare lo stesso approccio di configurazione? Se sì, voglio dire che mi sembra troppo ingegneristico.
Marius
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.