Je veux tester quelques fonctions incluses dans mon package principal, mais mes tests ne semblent pas pouvoir accéder à ces fonctions.
Mon exemple de fichier main.go ressemble à ceci:
package main
import (
"log"
)
func main() {
log.Printf(foo())
}
func foo() string {
return "Foo"
}
et mon fichier main_test.go ressemble à:
package main
import (
"testing"
)
func Foo(t testing.T) {
t.Error(foo())
}
quand je cours go test main_test.go
Je reçois
# command-line-arguments
.\main_test.go:8: undefined: foo
FAIL command-line-arguments [build failed]
Si je comprends bien, même si j'ai déplacé le fichier de test ailleurs et essayé d'importer à partir du fichier main.go, je ne pouvais pas l'importer, car il est package main
.
Quelle est la bonne façon de structurer de tels tests? Dois-je simplement tout supprimer du package main
en plus d'une simple fonction principale pour tout exécuter, puis tester les fonctions dans leur propre package, ou existe-t-il un moyen pour moi d'appeler ces fonctions à partir du fichier principal pendant le test?
lorsque vous spécifiez des fichiers sur la ligne de commande, vous devez tous les spécifier
Voici ma course:
$ ls
main.go main_test.go
$ go test *.go
ok command-line-arguments 0.003s
note, dans ma version, j'ai couru avec main.go et main_test.go sur la ligne de commande
De plus, votre fichier _test n'est pas tout à fait correct, vous devez appeler votre fonction de test TestXXX et prendre un pointeur sur testing.
Voici la version modifiée:
package main
import (
"testing"
)
func TestFoo(t *testing.T) {
t.Error(foo())
}
et la sortie modifiée:
$ go test *.go
--- FAIL: TestFoo (0.00s)
main_test.go:8: Foo
FAIL
FAIL command-line-arguments 0.003s
Les tests unitaires ne vont que jusqu'à présent. À un moment donné, vous devez réellement exécuter le programme. Ensuite, vous testez qu'il fonctionne avec une entrée réelle, à partir de sources réelles, produisant une sortie réelle vers des destinations réelles. Pour de vrai.
Si vous voulez tester un élément, déplacez-le hors de main ().
C'est pas une réponse directe à la question de l'OP et je suis généralement d'accord avec les réponses et les commentaires précédents demandant que main
soit principalement un appelant de fonctions packagées. Cela étant dit, voici une approche que je trouve utile pour tester les exécutables. Il utilise log.Fataln
Et exec.Command
.
main.go
Avec une fonction différée qui appelle log.Fatalln () pour écrire un message à stderr avant de revenir.main_test.go
, Utilisez exec.Command(...)
et cmd.CombinedOutput()
pour exécuter votre programme avec des arguments choisis pour tester le résultat attendu.Par exemple:
func main() {
// Ensure we exit with an error code and log message
// when needed after deferred cleanups have run.
// Credit: https://medium.com/@matryer/golang-advent-calendar-day-three-fatally-exiting-a-command-line-tool-with-grace-874befeb64a4
var err error
defer func() {
if err != nil {
log.Fatalln(err)
}
}()
// Initialize and do stuff
// check for errors in the usual way
err = somefunc()
if err != nil {
err = fmt.Errorf("somefunc failed : %v", err)
return
}
// do more stuff ...
}
Dans main_test.go
, Un test pour, disons, de mauvais arguments qui devraient entraîner l'échec de somefunc
pourrait ressembler à:
func TestBadArgs(t *testing.T) {
var err error
cmd := exec.Command(yourprogname, "some", "bad", "args")
out, err := cmd.CombinedOutput()
sout := string(out) // because out is []byte
if err != nil && !strings.Contains(sout, "somefunc failed") {
fmt.Println(sout) // so we can see the full output
t.Errorf("%v", err)
}
}
Notez que err
de CombinedOutput()
est le code de sortie différent de zéro de log.Fatalln sous-le-capot appel à os.Exit(1)
. C'est pourquoi nous devons utiliser out
pour extraire le message d'erreur de somefunc
.
Le package exec
fournit également cmd.Run
Et cmd.Output
. Celles-ci peuvent être plus appropriées que cmd.CombinedOutput
Pour certains tests. Je trouve également utile d'avoir une fonction TestMain(m *testing.M)
qui effectue la configuration et le nettoyage avant et après l'exécution des tests.
func TestMain(m *testing.M) {
// call flag.Parse() here if TestMain uses flags
os.Mkdir("test", 0777) // set up a temporary dir for generate files
// Create whatever testfiles are needed in test/
// Run all tests and clean up
exitcode := m.Run()
os.RemoveAll("test") // remove the directory and its contents.
os.Exit(exitcode)