Qual è la differenza tra un mock & stub?


963

Ho letto vari articoli su derisione e stub nei test, tra cui Mock Aren't Stubs di Martin Fowler , ma ancora non capisco la differenza.



75
@OP Perché non c'è differenza. Questo articolo, per quanto amato dalla comunità, sta - con tutto il dovuto rispetto - rendendo tutto inutile confondendo aggiungendo un significato aggiuntivo alle parole che sono facili da capire altrimenti e rendendo le cose inutili complicate. Il finto è solo un finto, qualcosa che esegue una falsa logica aziendale invece di una vera. Controllare il comportamento alla fine è una tua scelta, ma è ancora una finta. O come vuoi chiamarlo, ma fallo UNO. Non dividere i peli. Mantienilo semplice, in modo che le persone possano capire facilmente il tuo concetto, con cui l'articolo sopra non fallisce.
wst

10
"La classificazione tra beffe, falsi e tronconi è altamente incoerente in tutta la letteratura." Con molte citazioni. Ancora una delle mie citazioni preferite di Wikipedia - se esiste una cosa del genere :) en.wikipedia.org/wiki/Mock_object
JD.

11
l'articolo di Martin Fowler è davvero difficile da capire per i principianti.
lmiguelvargasf,

1
Il modo in cui capisco è che uno stub sarebbe solo un oggetto da buttare per il test, come una raccolta di dati fittizi. Un Mock sarebbe una versione abilmente scavalcata di qualcosa di più complesso, come un livello di servizio con vari metodi, di cui potresti aver modificato il comportamento, per i tuoi test. Le due cose vengono usate insieme, come se potessi passare alcuni oggetti mozzati nel tuo livello deriso.
JsonStatham

Risposte:


746

mozzicone

Credo che la più grande distinzione sia che uno stub che hai già scritto con un comportamento predeterminato. Quindi avresti una classe che implementa la dipendenza (classe astratta o interfaccia molto probabilmente) che stai fingendo a scopo di test e i metodi verrebbero semplicemente eliminati con risposte impostate. Non farebbero niente di speciale e avresti già scritto il codice stubbing per farlo al di fuori del tuo test.

finto

Un finto è qualcosa che come parte del tuo test devi impostare con le tue aspettative. Un finto non è impostato in un modo predeterminato, quindi hai un codice che lo fa nel tuo test. Le simulazioni in un certo senso sono determinate in fase di esecuzione poiché il codice che imposta le aspettative deve essere eseguito prima di fare qualsiasi cosa.

Differenza tra mock e mozziconi

I test scritti con beffe di solito seguono un initialize -> set expectations -> exercise -> verifymodello di test. Mentre lo stub pre-scritto avrebbe seguito un initialize -> exercise -> verify.

Somiglianza tra Mock e Stub

Lo scopo di entrambi è quello di eliminare il test di tutte le dipendenze di una classe o di una funzione in modo che i test siano più focalizzati e più semplici in ciò che stanno cercando di dimostrare.


876

Prefazione

Esistono diverse definizioni di oggetti che non sono reali. Il termine generale è doppio del test . Questo termine comprende: manichino , falso , troncone , finto .

Riferimento

Secondo l'articolo di Martin Fowler :

  • Gli oggetti fittizi vengono fatti passare ma mai effettivamente utilizzati. Di solito vengono utilizzati solo per riempire elenchi di parametri.
  • Gli oggetti falsi in realtà hanno implementazioni funzionanti, ma di solito prendono alcuni collegamenti che li rendono non adatti alla produzione (un database in memoria è un buon esempio).
  • Gli stub forniscono risposte predefinite alle chiamate effettuate durante il test, di solito non rispondono a nulla al di fuori di ciò che è programmato per il test. Gli stub possono anche registrare informazioni sulle chiamate, come uno stub del gateway di posta elettronica che ricorda i messaggi che ha "inviato" o forse solo quanti messaggi ha "inviato".
  • Le finte sono ciò di cui stiamo parlando qui: oggetti pre-programmati con aspettative che formano una specifica delle chiamate che dovrebbero ricevere.

Stile

Mock vs Stubs = Test comportamentali vs test di stato

Principio

Secondo il principio di Test solo una cosa per test , in un test possono esserci più tronchetti, ma generalmente c'è solo un finto.

Ciclo vitale

Prova il ciclo di vita con gli stub:

  1. Installazione - Prepara l'oggetto che viene testato e i suoi collaboratori stub.
  2. Esercizio: prova la funzionalità.
  3. Verifica stato: utilizzare gli assert per verificare lo stato dell'oggetto.
  4. Smontaggio: pulizia delle risorse.

Prova il ciclo di vita con simulazioni:

  1. Dati di installazione: preparare l'oggetto in fase di test.
  2. Aspettative di installazione - Prepara le aspettative in mock che viene utilizzato dall'oggetto primario.
  3. Esercizio: prova la funzionalità.
  4. Verifica aspettative : verifica che i metodi corretti siano stati richiamati in modo fittizio.
  5. Verifica stato: utilizzare gli assert per verificare lo stato dell'oggetto.
  6. Smontaggio: pulizia delle risorse.

Sommario

Sia i test di simulazione che quelli di stub danno una risposta alla domanda: qual è il risultato?

Anche i test con simulazioni sono interessati a: come è stato raggiunto il risultato?


Aspetta, le beffe restituiscono anche risposte in scatola? Perché altrimenti perché rispondono alla domanda?
AturSams,

Da quello che hai scritto posso dire che mock = stub + aspettative e verifiche, perché i mock "forniscono risposte predefinite alle chiamate effettuate durante il test, di solito non rispondono affatto a qualsiasi cosa al di fuori di ciò che è programmato per il test" (uguale agli stub). E l'esempio che Fowler ha mostrato come esempio di uno stub è in realtà un esempio di spia! Ciò significa che un finto è un troncone e una spia è un troncone. E uno stub è solo un oggetto che ha diversi metodi di lavoro. Ciò spiega anche perché Mockito ha deprecato il metodo stub ().
kolobok,

Ciò che trovo confuso su questo e la risposta accettata è questa "impostazione delle aspettative", cosa significa anche? Di solito, nel "codice principale" crei i risultati che ti aspetteresti. Sembra che tu abbia messo le aspettative in qualche modo nell'oggetto finto, il che non ha senso per me. Inoltre, potresti anche esercitare la simulazione con un po 'di input, archiviare il risultato, creare "le aspettative" in un secondo momento e quindi confrontare. Usi una terminologia che trovo troppo astratta e ambigua.
IceFire

365

Uno stub è un semplice oggetto falso. Si assicura solo che il test venga eseguito senza problemi.
Un finto è un troncone più intelligente. Verifica che il tuo test lo superi.


33
Penso che questa sia la risposta più concisa e puntuale. Takeaway: un finto troncone IS-A. stackoverflow.com/a/17810004/2288628 è la versione più lunga di questa risposta.
PoweredByRice

8
Non penso che un finto sia uno stub. I mock sono usati per affermare e non dovrebbero mai restituire dati, gli stub sono usati per restituire dati e non dovrebbero mai affermare.
dave1010,

2
@ dave1010 Le beffe sicuramente possono restituire dati o persino generare un'eccezione. Dovrebbero farlo in risposta ai parametri passati in essi.
Trenton,

2
@trenton se un oggetto ritorna o genera in base ai dati trasmessi, allora è un falso , non un finto. Gli stub testano il modo in cui il SUT gestisce la ricezione dei messaggi, mentre i mock testano il modo in cui il SUT invia i messaggi. Mischiare i 2 probabilmente porterà a un cattivo design OO.
dave1010,

8
Penso che sia fantastico: uno stub restituisce le risposte alle domande. Un mock restituisce anche le risposte alle domande (is-a stub) ma verifica anche che la domanda sia stata posta !!
Leif,

238

Ecco una descrizione di ciascuno seguita da un campione del mondo reale.

  • Manichino - solo valori fasulli per soddisfare il API.

    Esempio : se si sta testando un metodo di una classe che richiede molti parametri obbligatori in un costruttore che non hanno alcun effetto sul test, è possibile creare oggetti fittizi allo scopo di creare nuove istanze di una classe.

  • Falso : crea un'implementazione di prova di una classe che potrebbe dipendere da un'infrastruttura esterna. (È buona norma che il test unitario NON interagisca effettivamente con l'infrastruttura esterna.)

    Esempio : creare un'implementazione falsa per accedere a un database, sostituirlo con la in-memoryraccolta.

  • Stub : sovrascrive i metodi per restituire valori codificati, indicati anche come state-based.

    Esempio : la classe di test dipende dal completamento di un metodo che Calculate()richiede 5 minuti. Invece di attendere 5 minuti, è possibile sostituire la sua vera implementazione con stub che restituisce valori codificati; prendendo solo una piccola parte del tempo.

  • Finto - molto simile Stubma interaction-basedpiuttosto che basato sullo stato. Ciò significa che non ti aspetti Mockdi restituire un valore, ma di presumere che vengano effettuate specifiche chiamate di metodo.

    Esempio: stai testando una classe di registrazione utente. Dopo aver chiamato Save, dovrebbe chiamare SendConfirmationEmail.

Stubse in Mocksrealtà sono sottotipi di Mock, entrambi scambiano l'implementazione reale con l'implementazione del test, ma per motivi diversi e specifici.


175

Nel corso codeschool.com , Rails Testing for Zombies , danno questa definizione dei termini:

mozzicone

Per sostituire un metodo con codice che restituisce un risultato specificato.

finto

Uno stub con un'affermazione che il metodo viene chiamato.

Quindi, come ha descritto Sean Copenhaver nella sua risposta, la differenza è che le beffe fissano aspettative (cioè fanno affermazioni, se o come vengono chiamate).


Per completare il post di Dillon, pensaci, hai una classe chiamata "MakeACake" che prende diverse biblioteche: latte, uova, zucchero, forno.
aarkerio,

139

Gli stub non falliscono i tuoi test, finto possibile.


2
E penso che sia buono, sai se i test hanno lo stesso comportamento dopo il refactoring.
RodriKing,

1
@RodriKing Ho la stessa sensazione. Come nel caso di Mock, con eventuali modifiche al codice di produzione, sono presenti modifiche corrispondenti al codice di prova. Qual è il dolore! Con Stub, ti sembra di continuare a testare il comportamento, quindi non è necessario apportare micro modifiche con il codice di test.
tucq88,

35

Penso che la risposta più semplice e chiara a questa domanda sia data da Roy Osherove nel suo libro The art of Unit Testing (pagina 85)

Il modo più semplice per dire che abbiamo a che fare con uno stub è notare che lo stub non può mai fallire il test. Le asserzioni che il test usa sono sempre contro la classe sotto test.

D'altra parte, il test utilizzerà un oggetto simulato per verificare se il test ha avuto esito negativo o meno. [...]

Ancora una volta, l'oggetto finto è l'oggetto che usiamo per vedere se il test fallisce o no.

Ciò significa che se stai affermando contro il falso significa che stai usando il falso come un finto, se stai usando il falso solo per eseguire il test senza affermazione su di esso stai usando il falso come un troncone.


2
Vorrei che la tua risposta arrivasse in cima. Ecco R. Osherove che spiega questo youtu.be/fAb_OnooCsQ?t=1006 .
Michael Ekoka,

31

Leggendo tutte le spiegazioni sopra, fammi provare a condensare:

  • Stub : un codice fittizio che consente l'esecuzione del test, ma non ti interessa cosa succede.
  • Mock : un codice fittizio, che VERIFY viene chiamato correttamente come parte del test.
  • Spia : un codice fittizio che intercetta alcune chiamate verso un codice reale, permettendoti di verificare le chiamate senza sostituire l'intero oggetto originale.

4
Buona risposta. Il finto suona abbastanza simile a quello di Spy, in base alla tua definizione. Sarebbe bello se hai aggiornato la tua risposta per includere qualche altro doppio di prova.
Rowan Gontier,

Non avevo sentito parlare di Spy quando ho scritto questa risposta.
O'Rooney,

23

Un Mock sta solo testando il comportamento, assicurandosi che vengano chiamati determinati metodi. Uno stub è una versione verificabile (di per sé) di un particolare oggetto.

Cosa intendi con Apple?


19
"Cosa intendi con Apple?" Usa Helvetica
kubi l'

7
In un modo Apple anziché in un modo Microsoft :)
never_had_a_name l'

2
Questo aiuta la situazione?
NebulaFox,

21

Se lo confronti con il debug:

Stub è come assicurarsi che un metodo restituisca il valore corretto

Mock è come entrare nel metodo e assicurarsi che tutto all'interno sia corretto prima di restituire il valore corretto.


20

Utilizzando un modello mentale mi ha davvero aiutato a capire questo, piuttosto che tutte le spiegazioni e gli articoli, che non si è "affondato".

Immagina che tuo figlio abbia una lastra di vetro sul tavolo e inizi a giocarci. Ora, hai paura che si rompa. Quindi, invece, gli dai un piatto di plastica. Sarebbe una simulazione (stesso comportamento, stessa interfaccia, implementazione "più morbida").

Ora, supponi di non avere la sostituzione in plastica, quindi spieghi "Se continui a giocarci, si romperà!". Questo è uno stub , hai fornito in anticipo uno stato predefinito.

Un manichino sarebbe la forchetta che non ha nemmeno usato ... e una spia potrebbe essere qualcosa come fornire la stessa spiegazione che hai già usato che ha funzionato.


19

Penso che la differenza più importante tra loro sia le loro intenzioni.

Vorrei provare a spiegarlo in WHY stub vs. WHY mock

Supponiamo che stia scrivendo un codice di prova per il controller della cronologia pubblica del mio client mac twitter

Ecco il codice di esempio di prova

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB: La connessione di rete all'API di Twitter è molto lenta, il che rende lento il mio test. So che restituirà le tempistiche, quindi ho creato uno stub che simula l'API HTTP di Twitter, in modo che il mio test lo esegua molto velocemente e posso eseguirlo anche se sono offline.
  • MOCK: Non ho ancora scritto nessuno dei miei metodi di interfaccia utente e non sono sicuro di quali metodi devo scrivere per il mio oggetto dell'interfaccia utente. Spero di sapere come il mio controller collaborerà con il mio oggetto UI scrivendo il codice di prova.

Scrivendo finto, scopri la relazione di collaborazione degli oggetti verificando che le aspettative siano soddisfatte, mentre il troncone simula solo il comportamento dell'oggetto.

Suggerisco di leggere questo articolo se stai cercando di saperne di più sui mock: http://jmock.org/oopsla2004.pdf


1
Penso che tu abbia l'idea giusta, ma Dillon Kearns l'ha spiegato molto più chiaramente.
O'Rooney,

19

Per essere molto chiari e pratici:

Stub: una classe o un oggetto che implementa i metodi della classe / oggetto da falsificare e restituisce sempre ciò che si desidera.

Esempio in JavaScript:

var Stub = {
   method_a: function(param_a, param_b){
      return 'This is an static result';
   }
}

Mock: lo stesso di stub, ma aggiunge una logica che "verifica" quando viene chiamato un metodo in modo da poter essere certi che qualche implementazione stia chiamando quel metodo.

Come dice @mLevan, immagina come esempio che stai testando una classe di registrazione utente. Dopo aver chiamato Salva, dovrebbe chiamare SendConfirmationEmail.

Un codice molto stupido Esempio:

var Mock = {
   calls: {
      method_a: 0
   }

   method_a: function(param_a, param_b){
     this.method_a++; 
     console.log('Mock.method_a its been called!');
   }
}

16

Questa diapositiva spiega molto bene le principali differenze.

inserisci qui la descrizione dell'immagine

* Da CSE 403 Lecture 16, University of Washington (slide creata da "Marty Stepp")


Questa è la spiegazione più chiara della differenza tra i due, IMO. Per lo stub: il tester prende lo Stub e lo usa direttamente all'interno della classe sotto test. Ma per Mock, il tester deve capire come verrà utilizzato l'oggetto Mock. In diversi casi, si comporterà diversamente. Al contrario, non si prevede che lo stub si comporti in modo diverso, ma viene utilizzato così com'è (ovvero restituendo gli stessi dati ogni volta che viene contattato)
Dexter,

12

Mi piace la spiegazione fornita da Roy Osherove [collegamento video] .

Ogni classe o oggetto creato è un falso. È un Mock se si verificano chiamate contro di esso. Altrimenti è un troncone.


12
  • Stub vs. Mock
    • stubs
      1. fornire risposte specifiche alle chiamate dei metodi
        • es: myStubbedService.getValues ​​() restituisce solo una stringa richiesta dal codice in prova
      2. utilizzato dal codice in prova per isolarlo
      3. impossibile fallire il test
        • es: myStubbedService.getValues ​​() restituisce semplicemente il valore stubbed
      4. spesso implementano metodi astratti
    • Mocks
      1. "superset" di tronconi; può affermare che alcuni metodi sono chiamati
        • es: verifica che myMockedService.getValues ​​() venga chiamato una sola volta
      2. utilizzato per testare il comportamento del codice in prova
      3. può fallire il test
        • es: verifica che myMockedService.getValues ​​() sia stato chiamato una volta; la verifica non riesce, perché myMockedService.getValues ​​() non è stato chiamato dal mio codice testato
      4. spesso prende in giro le interfacce

11

vediamo Doppi test:

  • Falso : i falsi sono oggetti con implementazioni funzionanti, ma non uguali a quello di produzione. Ad esempio : implementazione in memoria di Data Access Object o Repository.
  • Stub : Stub è un oggetto che contiene dati predefiniti e lo utilizza per rispondere alle chiamate durante i test. Ad esempio : un oggetto che deve acquisire alcuni dati dal database per rispondere a una chiamata del metodo.

  • Mock : i mock sono oggetti che registrano le chiamate che ricevono. Nell'affermazione di prova, possiamo verificare su Mock che tutte le azioni previste sono state eseguite. Ad esempio : una funzionalità che chiama il servizio di invio di posta elettronica. per di più basta controllare questo .


1
migliore risposta secondo me
Ero Stefano il

9

Un falso è un termine generico che può essere utilizzato per descrivere uno stub o un oggetto finto (scritto a mano o in altro modo), perché entrambi sembrano l'oggetto reale.

Se un falso è uno stub o un finto dipende da come viene utilizzato nel test corrente. Se viene usato per verificare un'interazione (asserito contro), è un oggetto finto. Altrimenti, è un troncone.

Fakes assicura che il test venga eseguito senza problemi. Significa che il lettore del tuo test futuro capirà quale sarà il comportamento dell'oggetto falso, senza bisogno di leggere il suo codice sorgente (senza dipendere da risorse esterne).

Cosa significa eseguire correttamente i test?
Esempio di esempio nel codice seguente:

 public void Analyze(string filename)
        {
            if(filename.Length<8)
            {
                try
                {
                    errorService.LogError("long file entered named:" + filename);
                }
                catch (Exception e)
                {
                    mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                }
            }
        }

Vuoi testare il metodo mailService.SendEMail () , per fare ciò devi simulare un'eccezione nel tuo metodo di test, quindi devi solo creare una classe errorSub Fake Stub per simulare quel risultato, quindi il tuo codice di test sarà in grado di testare metodo mailService.SendEMail (). Come vedi, devi simulare un risultato che proviene da un'altra classe ErrorService di dipendenza esterna.


8

Proprio dalla carta Ruoli Mock, non oggetti , dagli sviluppatori di jMock:

Gli stub sono implementazioni fittizie del codice di produzione che restituiscono risultati predefiniti. Gli oggetti simulati agiscono come tronconi, ma includono anche asserzioni per strumentare le interazioni dell'oggetto bersaglio con i suoi vicini.

Quindi, le differenze principali sono:

  • le aspettative impostate sugli stub sono generalmente generiche, mentre le aspettative sulle simulazioni possono essere più "intelligenti" (ad es. restituire questo alla prima chiamata, questo alla seconda ecc.).
  • gli stub sono principalmente usati per impostare input indiretti del SUT , mentre i mock possono essere usati per testare sia input indiretti che output indiretti del SUT.

Per riassumere, cercando anche di dissipare la confusione dal titolo dell'articolo di Fowler : le beffe sono tronconi, ma non sono solo tronconi .


1
penso che tu abbia ragione, ma è per questo che l'articolo di Fowler è confuso, il titolo dell'articolo è "Mocks Aren't Stubs" ... ma SONO ?! ¯_ (ツ) _ / ¯
stonedauwg

@stonedauwg, infatti, ho modificato il mio post per incorporare il tuo gioco di parole e un chiarimento. Spero che questo aiuti un po 'di più.
Dimos,

@stonedauwg, un finto non è un troncone, proprio come un rettangolo non è un quadrato. :)
seanriordan08

7

Stavo leggendo The Art of Unit Testing e mi sono imbattuto nella seguente definizione:

Un falso è un termine generico che può essere utilizzato per descrivere uno stub o un oggetto finto (scritto a mano o in altro modo), perché entrambi sembrano l'oggetto reale. Se un falso è uno stub o un finto dipende da come viene utilizzato nel test corrente. se è usato per controllare un'interazione (asserito contro), è un oggetto finto . Altrimenti, è un troncone .


5

Mi sono imbattuto in questo interessante articolo di UncleBob The Little Mocker . Spiega tutta la terminologia in un modo molto facile da capire, quindi è utile per i principianti. L'articolo di Martin Fowlers è una lettura difficile soprattutto per i principianti come me.


4

mozzicone ci aiuta a eseguire il test. Come? Fornisce valori che aiutano a eseguire il test. Questi valori non sono reali e abbiamo creato questi valori solo per eseguire il test. Ad esempio creiamo una HashMap per darci valori simili a quelli nella tabella del database. Quindi, invece di interagire direttamente con il database, interagiamo con Hashmap.

Il finto è un oggetto falso che esegue il test. dove abbiamo affermato.


"Quindi, invece di interagire direttamente con il database, interagiamo con Hashmap." ... perché non avevamo ancora tempo per codificare il modulo database e non abbiamo potuto eseguire il codice test senza usare lo stub. Altrimenti lo stesso Hasmap sarebbe una beffa! destra?
Boris Däppen,

4

Vedi sotto esempio di mock vs stub usando framework C # e Moq. Moq non ha una parola chiave speciale per Stub ma puoi usare anche l'oggetto Mock per creare stub.

namespace UnitTestProject2
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    [TestClass]
    public class UnitTest1
    {
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));

            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
        }
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(0);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
        }
        /// <summary>
        /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
        {
            // Arrange 
            var stubEntityRepository = new Mock<IEntityRepository>();
            stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                .Returns("Stub");
            const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
            var entity = new EntityClass(stubEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
        }
    }
    public class EntityClass
    {
        private IEntityRepository _entityRepository;
        public EntityClass(IEntityRepository entityRepository)
        {
            this._entityRepository = entityRepository;
        }
        public string Name { get; set; }
        public string GetNameWithPrefix(int id)
        {
            string name = string.Empty;
            if (id > 0)
            {
                name = this._entityRepository.GetName(id);
            }
            return "Mr. " + name;
        }
    }
    public interface IEntityRepository
    {
        string GetName(int id);
    }
    public class EntityRepository:IEntityRepository
    {
        public string GetName(int id)
        {
            // Code to connect to DB and get name based on Id
            return "NameFromDb";
        }
    }
}

4

Punto di vista del test Stub e Mock:

  • Stub è un'implementazione fittizia eseguita dall'utente in modo statico , ovvero quando Stub scrive il codice di implementazione. Quindi non è in grado di gestire la definizione del servizio e le condizioni dinamiche, normalmente ciò avviene nel framework JUnit senza usare il framework beffardo.

  • Mock è anche un'implementazione fittizia ma la sua implementazione ha fatto un modo dinamico usando framework Mocking come Mockito. Quindi possiamo gestire la definizione delle condizioni e del servizio come un modo dinamico, cioè i mock possono essere creati dinamicamente dal codice in fase di esecuzione. Quindi usando la simulazione possiamo implementare gli Stub in modo dinamico.


3

Più risposte utili, uno dei punti più potenti dell'uso di Mocks of Subs

Se il collaboratore [da cui dipende il codice principale] non è sotto il nostro controllo (ad es. Da una libreria di terze parti),
In questo caso, stub è più difficile da scrivere piuttosto che deridere .


2

Ho usato esempi di Python nella mia risposta per illustrare le differenze.

Stub - Stubbing è una tecnica di sviluppo software utilizzata per implementare metodi di classi all'inizio del ciclo di vita dello sviluppo. Vengono utilizzati comunemente come segnaposto per l'implementazione di un'interfaccia nota, in cui l'interfaccia è finalizzata o nota ma l'implementazione non è ancora nota o finalizzata. Inizi con gli stub, il che significa semplicemente che scrivi la definizione di una funzione e lasci il codice effettivo per dopo. Il vantaggio è che non dimenticherai i metodi e puoi continuare a pensare al tuo progetto mentre lo vedi nel codice. Puoi anche fare in modo che il tuo stub restituisca una risposta statica in modo che la risposta possa essere utilizzata immediatamente da altre parti del codice. Gli oggetti Stub forniscono una risposta valida, ma è statico indipendentemente dall'input che passi, otterrai sempre la stessa risposta:

class Foo(object):
    def bar1(self):
        pass

    def bar2(self):
        #or ...
        raise NotImplementedError

    def bar3(self):
        #or return dummy data
        return "Dummy Data"

finto oggetti vengono utilizzati in casi di test simulati e convalidano il fatto che determinati metodi vengano chiamati su tali oggetti. Gli oggetti simulati sono oggetti simulati che imitano il comportamento di oggetti reali in modo controllato. Generalmente si crea un oggetto simulato per testare il comportamento di qualche altro oggetto. Le simulazioni ci permettono di simulare risorse che non sono disponibili o troppo ingombranti per i test unitari.

mymodule.py:

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

test.py:

from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase):
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")
        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

if __name__ == '__main__':
    unittest.main()

Questo è un esempio molto semplice che esegue semplicemente rm e afferma il parametro con cui è stato chiamato. Puoi usare mock con oggetti non solo funzioni come mostrato qui, e puoi anche restituire un valore così un oggetto mock può essere usato per sostituire uno stub per il test.

Altro su unittest.mock , la nota in python 2.x mock non è inclusa in unittest ma è un modulo scaricabile che può essere scaricato tramite pip (pip install mock).

Ho anche letto "The Art of Unit Testing" di Roy Osherove e penso che sarebbe fantastico se un libro simile venisse scritto usando esempi di Python e Python. Se qualcuno conosce un libro del genere, ti preghiamo di condividere. Saluti :)


2

Uno stub è un oggetto falso creato a scopo di test. Un mock è uno stub che registra se si sono effettivamente verificate chiamate attese.


2

Uno stub è una funzione vuota che viene utilizzata per evitare eccezioni non gestite durante i test:

function foo(){}

Una simulazione è una funzione artificiale che viene utilizzata per evitare dipendenze del sistema operativo, dell'ambiente o dell'hardware durante i test:

function foo(bar){ window = this; return window.toString(bar); }

In termini di affermazioni e stato:

  • I falsi sono asseriti prima di un evento o di un cambio di stato
  • Gli stub non sono affermati, forniscono lo stato prima di un evento per evitare l'esecuzione di codice da unità non correlate
  • Le spie sono impostate come stub, quindi asserite dopo un evento o un cambio di stato
  • I falsi non vengono affermati, ma vengono eseguiti dopo un evento con dipendenze codificate per evitare lo stato

Riferimenti


2
+1 per l'aggiunta di spie al glossario. Inoltre, penso che intendi "Le spie sono installate come beffe" e non "Le spie sono installate come tronconi"
Sameh Deabes,


2

Un finto è sia un oggetto tecnico che funzionale .

La simulazione è tecnica . È infatti creato da una libreria beffarda (EasyMock, JMockit e più recentemente Mockito sono noti per questi) grazie alla generazione del codice byte .
L'implementazione fittizia viene generata in un modo in cui potremmo strumentarla per restituire un valore specifico quando viene invocato un metodo, ma anche altre cose come la verifica che un metodo simulato sia stato invocato con alcuni parametri specifici (controllo rigoroso) o qualunque sia il parametro ( nessun controllo rigoroso).

Istantanea di un finto:

@Mock Foo fooMock

Registrare un comportamento:

when(fooMock.hello()).thenReturn("hello you!");

Verifica di una chiamata:

verify(fooMock).hello()

Questi chiaramente non sono il modo naturale di istanziare / scavalcare la classe / il comportamento di Foo. Ecco perché mi riferisco ad un aspetto tecnico.

Ma la simulazione è anche funzionale perché è un'istanza della classe che dobbiamo isolare dal SUT. E con comportamenti registrati su di esso, potremmo usarlo nel SUT allo stesso modo di come faremmo con uno stub.


Lo stub è solo un oggetto funzionale : questa è un'istanza della classe che dobbiamo isolare dal SUT e basta. Ciò significa che sia la classe stub che tutti i dispositivi di comportamento necessari durante i nostri test unitari devono essere definiti in modo esplicito.
Ad esempio per stub hello()sarebbe necessario sottoclassare la Fooclasse (o implementare la sua interfaccia ce l'ha) e sovrascrivere hello() :

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

Se un altro scenario di test richiede un altro valore restituito, probabilmente avremmo bisogno di definire un modo generico per impostare il rendimento:

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

Altro scenario: se avessi avuto un metodo di effetto collaterale (nessun ritorno) e avrei verificato che quel metodo fosse invocato, avrei probabilmente aggiunto un valore booleano o un contatore nella classe stub per contare quante volte è stato invocato il metodo.


Conclusione

Lo stub richiede spesso molto overhead / codice per scrivere per il test unitario. Ciò che il finto impedisce grazie alla fornitura immediata di funzionalità di registrazione / verifica.
Ecco perché al giorno d'oggi l'approccio stub viene raramente utilizzato in pratica con l'avvento di eccellenti librerie finte.


Informazioni sull'articolo di Martin Fowler: Non penso di essere un programmatore "beffardo" mentre uso le beffe ed evito gli stub.
Ma uso il finto quando è veramente necessario (dipendenze fastidiose) e preferisco i test di suddivisione in test e mini-integrazione quando collaudo una classe con dipendenze che il deridere sarebbe un sovraccarico.

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.