Denominazione corretta dei pacchetti per i test con il linguaggio Go


102

Ho visto diverse strategie di denominazione dei pacchetti di test all'interno di Go e volevo sapere quali sono i pro ei contro di ciascuno e quale dovrei usare.

Strategia 1:

Nome file: github.com/user/myfunc.go

package myfunc

Nome del file di prova: github.com/user/myfunc_test.go

package myfunc

Vedi bzip2 per un esempio.

Strategia 2:

Nome file: github.com/user/myfunc.go

package myfunc

Nome del file di prova: github.com/user/myfunc_test.go

package myfunc_test

import (
    "github.com/user/myfunc"
)

Vedi filo per un esempio.

Strategia 3:

Nome file: github.com/user/myfunc.go

package myfunc

Nome del file di prova: github.com/user/myfunc_test.go

package myfunc_test

import (
    . "myfunc"
)

Vedi stringhe per un esempio.

La libreria standard Go sembra utilizzare una combinazione di strategia 1 e 2. Quale delle tre dovrei usare? È un package *_testproblema aggiungere ai miei pacchetti di test perché significa che non posso testare i metodi privati ​​dei miei pacchetti, ma forse c'è un vantaggio nascosto di cui non sono a conoscenza?


9
Questa domanda si tradurrà solo in opinioni diverse, ma aggiungerò la mia. Non dovresti aver bisogno di testare i tuoi metodi privati. Vuoi testare l'interfaccia del tuo pacchetto che altri sviluppatori utilizzeranno. Se i test falliscono, allora sai che i tuoi metodi privati ​​hanno bisogno di uno sguardo.
Brenden

2
L'esempio [wire] ( github.com/btcsuite/btcd/blob/master/wire/msgtx_test.go ) per la strategia 2, è attualmente anche un esempio di strategia 1 ...
durp

Risposte:


130

La differenza fondamentale tra le tre strategie che hai elencato è se il codice di test si trova o meno nello stesso pacchetto del codice sotto test. La decisione di utilizzare package myfunco package myfunc_testnel file di test dipende dal fatto che si desideri eseguire il test white box o black box .

Non c'è niente di sbagliato nell'usare entrambi i metodi in un progetto. Ad esempio, potresti avere myfunc_whitebox_test.goemyfunx_blackbox_test.go .

Confronto dei pacchetti di codice di prova

  • Test della scatola nera: utilizzare package myfunc_test, che assicurerà di utilizzare solo gli identificatori esportati .
  • Test white box: utilizzare in package myfuncmodo da avere accesso agli identificatori non esportati. Ideale per gli unit test che richiedono l'accesso a variabili, funzioni e metodi non esportati.

Confronto delle strategie elencate in questione

  • Strategia 1: il file myfunc_test.goutilizza package myfunc: in questo caso il codice di test in myfunc_test.gosarà nello stesso pacchetto del codice in fase di test myfunc.go, che è myfuncin questo esempio.
  • Strategia 2: il file myfunc_test.goutilizza package myfunc_test- In questo caso il codice di test in myfunc_test.go"verrà compilato come pacchetto separato, quindi collegato ed eseguito con il binario di test principale." [Fonte: righe 58-59 nel codice sorgente test.go ]
  • Strategia 3: il file myfunc_test.goutilizza package myfunc_testma importa myfuncutilizzando la notazione a punti - Questa è una variante della strategia 2, ma utilizza la notazione a punti per l'importazione myfunc.

1
Va notato che l'utilizzo della Strategia 1 manterrà anche i file _test.goseparati dal pacchetto testato (lo stesso comportamento della Strategia 2). Questo non sembra essere documentato da github.com/golang/go/issues/15315
Kevin Deenanauth,

Ho visto un forte utilizzo del pacchetto Strategia 3, ma non riesco a capire qual è il punto?
PickBoy

1
Ho biforcato un pacchetto e apportato modifiche, e ora i miei test stanno provando tutti a importare il repository originale invece del mio pacchetto biforcato. Con la strategia 3, non devo cambiare "github.com/original/link" in "github.com/my/fork", perché si riferisce solo a "." anziché.
nmarley

1
@KevinDeenanauth Questo mi ha semplicemente sorpreso. Pensavo di aver trovato una trappola quando ho appena trovato un _test.gocon un _testnome non di pacchetto contenente a func init()che cambia alcune variabili globali del pacchetto per il test. Mi sbagliavo.
Zyl

1
@nmarley il .non risolve il problema della forcella. Non è un'importazione relativa. Importa solo gli identificatori "nel pacchetto corrente".
qaisjp

19

Dipende dalla portata dei tuoi test. I test di alto livello (integrazione, accettazione, ecc ...) dovrebbero probabilmente essere collocati in un pacchetto separato per assicurarsi di utilizzare il pacchetto tramite l'API esportata.

Se hai un pacchetto di grandi dimensioni con molti interni che devono essere testati, usa lo stesso pacchetto per i tuoi test. Ma questo non è un invito per i tuoi test ad accedere a qualsiasi parte dello stato privato. Ciò renderebbe il refactoring un incubo. Quando scrivo struct in go , spesso implemento interfacce. Sono quei metodi di interfaccia che invoco dai miei test, non tutti i metodi / funzioni di supporto individualmente.


13

Dovresti usare la strategia 1 quando possibile. È possibile utilizzare il foo_testnome del pacchetto speciale per evitare cicli di importazione, ma è per lo più lì, quindi la libreria standard può essere testata con lo stesso meccanismo. Ad esempio, stringsnon può essere testato con la strategia 1 poiché il testingpacchetto dipende da strings. Come hai detto, con la strategia 2 o 3 non hai accesso agli identificatori privati ​​del pacchetto, quindi di solito è meglio non usarlo a meno che non sia necessario.


10
In che modo non avere accesso a identificatori privati ​​nei test non è una virtù?
jub0bs

3
secondo buone pratiche di test, non si testano i dettagli di implementazione interna per un artefatto di codice; fare figlio, è un odore di codice
Gerardo Lima

0

Una nota importante che vorrei aggiungere import .da Golang CodeReviewComments :

Il import .modulo può essere utile nei test che, a causa di dipendenze circolari , non possono essere inseriti nel pacchetto in prova:

package foo_test

import (
    "bar/testutil" // also imports "foo"
    . "foo"
)

In questo caso, il file di test non può essere nel pacchetto foo perché usa bar/testutil, che importa foo. Quindi usiamo "import". form per far fingere che il file faccia parte del pacchetto pippo anche se non lo è.

Ad eccezione di questo caso, non utilizzareimport . nei tuoi programmi. Rende i programmi molto più difficili da leggere perché non è chiaro se un nome come Quux sia un identificatore di primo livello nel pacchetto corrente o in un pacchetto importato.

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.