178 votes

Se moquer de fonctions dans Golang

Je suis en train d'apprendre Passer par le codage d'un petit projet personnel. Même si elle est petite, j'ai décidé de faire rigoureux de tests unitaires pour apprendre de bonnes habitudes en Aller dès le début.

Trivial tests unitaires ont été tous très bien et dandy, mais je suis perplexe avec dépendances maintenant; je veux être en mesure de remplacer certains appels de fonction à la maquette. Voici un extrait de mon code:

func get_page(url string) string {
    get_dl_slot(url)
    defer free_dl_slot(url)

    resp, err := http.Get(url)
    if err != nil { return "" }
    defer resp.Body.Close()

    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil { return "" }
    return string(contents)
}

func downloader() {
    dl_slots = make(chan bool, DL_SLOT_AMOUNT) // Init the download slot semaphore
    content := get_page(BASE_URL)
    links_regexp := regexp.MustCompile(LIST_LINK_REGEXP)
    matches := links_regexp.FindAllStringSubmatch(content, -1)
    for _, match := range matches{
        go serie_dl(match[1], match[2])
    }
}

J'aimerais pouvoir tester downloader() sans réellement obtenir une page via http à - dire en se moquant soit get_page (plus facile car elle renvoie simplement le contenu de la page comme une chaîne de caractères) ou http.Get().

J'ai trouvé ce fil: https://groups.google.com/forum/#!topic/golang-noix/6AN1E2CJOxI qui semble être sur un problème similaire. Julian Phillips présente sa bibliothèque, Withmock (http://github.com/qur/withmock) comme une solution, mais je ne suis pas en mesure de l'obtenir pour fonctionner. Voici les parties pertinentes de mon code de test, qui est en grande partie de culte du cargo code pour moi, pour être honnête:

import (
    "testing"
    "net/http" // mock
    "code.google.com/p/gomock"
)
...
func TestDownloader (t *testing.T) {
    ctrl := gomock.NewController()
    defer ctrl.Finish()
    http.MOCK().SetController(ctrl)
    http.EXPECT().Get(BASE_URL)
    downloader()
    // The rest to be written
}

La sortie du test est la suivante:

ERROR: Failed to install '_et/http': exit status 1
output:
can't load package: package _et/http: found packages http (chunked.go) and main (main_mock.go) in /var/folders/z9/ql_yn5h550s6shtb9c5sggj40000gn/T/withmock570825607/path/src/_et/http

Est le Withmock une solution à mon test de problème? Que dois-je faire pour le faire fonctionner?

233voto

weberc2 Points 1584

Bravo à vous pour la bonne pratique des essais! :)

Personnellement, je n'utilise pas d' gomock (ou tout moqueur cadre de cette affaire; se moquant de Go est très facile de s'en passer). Je voudrais passer d'une dépendance à l' downloader() de la fonction en tant que paramètre, ou je ferais downloader() une méthode sur un type, et le type peut contenir l' get_page dépendance:

Méthode 1: Transmettre get_page() comme un paramètre d' downloader()

type PageGetter func(url string) string

func downloader(pageGetterFunc PageGetter) {
    // ...
    content := pageGetterFunc(BASE_URL)
    // ...
}

Principales:

func get_page(url string) string { /* ... */ }

func main() {
    downloader(get_page)
}

Test:

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader(t *testing.T) {
    downloader(mock_get_page)
}

Method2: Faire downloader() d'une méthode de type:

Si vous ne voulez pas passer de la dépendance en tant que paramètre, vous pouvez également en faire get_page() un membre d'un type, et font downloader() d'une méthode de ce type, qui peut alors l'utiliser get_page:

type PageGetter func(url string) string

type Downloader struct {
    get_page PageGetter
}

func NewDownloader(pg PageGetter) *Downloader {
    return &Downloader{get_page: pg}
}

func (d *Downloader) downloader() {
    //...
    content := d.get_page(BASE_URL)
    //...
}

Principales:

func get_page(url string) string { /* ... */ }

func main() {
    d := NewDownloader(get_page)
    d.downloader()
}

Test:

func mock_get_page(url string) string {
    // mock your 'get_page()' function here
}

func TestDownloader() {
    d := NewDownloader(mock_get_page)
    d.downloader()
}

40voto

Jake Points 939

Si vous modifiez la définition de fonction pour utiliser une variable à la place:

var get_page = func(url string) string {
    ...
}

Vous pouvez le remplacer dans vos tests:

func TestDownloader(t *testing.T) {
    get_page = func(url string) string {
        if url != "expected" {
            t.Fatal("good message")
        }
        return "something"
    }
    downloader()
}

Attention cependant, vos autres tests peuvent échouer si elles tester la fonctionnalité de la fonction vous remplacer!

-1voto

Gediminas Points 524

Ce qui concerne la maquette de la base de données

Il est un très commode paquet pour cette il a un sql pilote de mise en œuvre qui permet de facilement se moquer de toutes les bases de données liées à l'opération, avec des erreurs, des résultats du même argument de comparaison, qui, fondamentalement, est tout ce dont vous avez besoin pour assurer l'exécution correcte des flux de

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X