2013-09-23 10 views
20

parte del nostro codice è sensibile al tempo e abbiamo bisogno di qualcosa in grado di riservare e quindi rilasciarlo in 30-60 secondi, ecc, che possiamo solo fare un time.Sleep(60 * time.Second)C'è un modo semplice per spegnere il tempo. Ora() globalmente in golang durante il test?

interfaccia tempo

ho appena implementato e durante il test l'uso di un implementazione stubbed dell'interfaccia time, simile a this golang-nuts discussion.

Tuttavia, time.Now() viene chiamato in più siti, il che significa che è necessario passare una variabile in giro per tenere traccia di quanto tempo abbiamo effettivamente dormito.

Mi chiedevo se esiste un modo alternativo per escludere time.Now() a livello globale. Forse fare una chiamata di sistema per cambiare l'orologio di sistema?

Forse possiamo scrivere il nostro pacchetto di tempo che sostanzialmente avvolge il pacchetto temporale ma ci consente di cambiarlo?

La nostra attuale implementazione funziona bene, sono un principiante e sono curioso di vedere se qualcuno ha altre idee?

risposta

28

Con l'implementazione di un'interfaccia personalizzata, il numero è già sulla strada giusta. Io lo prendo di utilizzare il seguente consiglio dalle noci golang filo che hai postato:


type Clock interface { 
    Now() time.Time 
    After(d time.Duration) <-chan time.Time 
} 

e di fornire una concreta attuazione

type realClock struct{} 
func (realClock) Now() time.Time { return time.Now() } 
func (realClock) After(d time.Duration) <-chan time.Time { return time.After(d) } 

e un'implementazione di test .


Original

Modifica del tempo di sistema rendendo test (o in generale) è una cattiva idea. Non si sa cosa dipende dall'ora del sistema durante l'esecuzione dei test e non si vuole scoprire il modo più difficile trascorrendo giorni di debug in questo. Basta non farlo.

v'è anche un modo per ombra pacchetto tempo a livello globale e facendo questo non farebbe qualcosa di più non si poteva fare con la soluzione di interfaccia. È possibile scrivere il proprio pacco orario che utilizza la libreria standard e fornisce una funzione per passare a una libreria del tempo fittizio per il test se è l'oggetto orario necessario per passare con la soluzione dell'interfaccia che ti dà fastidio.

Il modo migliore per progettare e testare il codice sarebbe probabilmente quello di rendere il codice più stateless possibile. Dividi la tua funzionalità in parti testabili e senza stato. Testare questi componenti separatamente è molto più facile allora. Inoltre, meno effetti collaterali significa che è molto più facile far funzionare il codice contemporaneamente.

+6

Ho creato un pacchetto basato su questa idea: https://github.com/101loops/clock – stephanos

+1

@stephanos dovresti postarlo come risposta separata in quanto è facile non vederlo. Sarebbe utile anche l'uso di esempi sul repository stesso. –

4

Inoltre, se è necessario eseguire lo stub time.Now, è possibile inserire la dipendenza come funzione, ad es.

func moonPhase(now func() time.Time) { 
    if now == nil { 
    now = time.Now 
    } 

    // use now()... 
} 

// Then dependent code uses just 
moonPhase(nil) 

// And tests inject own version 
stubNow := func() time.Time { return time.Unix(1515151515, 0) } 
moonPhase(stubNow) 

Premesso tutto ciò che è un po 'brutto se si proviene da lingue sfondo dinamico (ad esempio Ruby) :(

11

uso il bouk/monkey package per sostituire i time.Now() chiamate nel mio codice con un falso:

package main 

import (
    "fmt" 
    "time" 

    "github.com/bouk/monkey" 
) 

func main() { 
    wayback := time.Date(1974, time.May, 19, 1, 2, 3, 4, time.UTC) 
    patch := monkey.Patch(time.Now, func() time.Time { return wayback }) 
    defer patch.Unpatch() 
    fmt.Printf("It is now %s\n", time.Now()) 
} 

Questo metodo funziona bene nei test di finto in dipendenze del sistema ed evita la abused DI pattern. codice di produzione rimane separato dal codice di prova e di ottenere il controllo utile di dipendenze del sistema.

0.123.
1

Se i metodi di cui avete bisogno per prendere in giro sono pochi, come ad esempio Now(), è possibile effettuare una variabile del pacchetto che può essere sovrascritto da test:

package foo 

import "time" 

var Now = time.Now 

// The rest of your code...which calls Now() instead of time.Now() 

poi nel file di test:

package foo 

import (
    "testing" 
    "time" 
) 

var Now = func() time.Time { return ... } 

// Your tests 
+0

Nota: non è necessario rendere pubblico ora perché sia ​​accessibile nei test. – Ramfjord

1

Dal risultato di Google ho trovato una soluzione relativamente semplice: Here

L'idea di base sta utilizzando un'altra chiamata di funzione "nowFunc" per ottenere l'ora. Ora(). Nel tuo main, inizializza questa funzione per restituire time.Now(). Nel test, inizializza questa funzione per restituire un tempo falso fisso.

Problemi correlati