Qual è la differenza tra un finto e stub?

Ho letto vari articoli su come eseguire il mocking e lo stubbing nei test, inclusi i Mock Are Stub di Martin Fowler , ma ancora non capisco la differenza.

mozzicone

Credo che la più grande distinzione sia quella di uno stub che hai già scritto con un comportamento predeterminato. Quindi si dovrebbe avere una class che implementa la dipendenza (la class astratta o l’interfaccia più probabile) che si sta fingendo a scopo di test e i metodi dovrebbero essere semplicemente eliminati con le risposte impostate. Non farebbero niente di speciale e avresti già scritto il codice stubbed al di fuori del tuo test.

finto

Un finto è qualcosa che come parte del tuo test devi configurare con le tue aspettative. Una simulazione non è impostata in modo predeterminato in modo da avere il codice che lo fa nel test. I mock in un modo sono determinati in fase di esecuzione poiché il codice che imposta le aspettative deve essere eseguito prima che facciano qualsiasi cosa.

Differenza

I test scritti con i mock di solito seguono un’inizializzazione initialize -> set expectations -> exercise -> verify modello per il test. Mentre lo stub pre-scritto seguirebbe un’inizializzazione initialize -> exercise -> verify .

Somiglianza

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

Prefazione

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

Riferimento

Secondo l’articolo di Martin Fowler :

  • Gli oggetti fittizi sono passati in giro ma mai effettivamente utilizzati. Solitamente sono solo usati per riempire gli elenchi dei parametri.
  • Gli oggetti finti hanno effettivamente implementazioni funzionanti, ma di solito prendono dei collegamenti che li rendono non adatti alla produzione (un database in memoria ne è un buon esempio).
  • Gli stub forniscono risposte predefinite alle chiamate fatte durante il test, di solito non rispondono affatto a nulla al di fuori di ciò che è stato programmato per il test. Gli stub possono anche registrare informazioni sulle chiamate, come uno stub del gateway email che ricorda i messaggi “inviati”, o forse solo il numero di messaggi “inviati”.
  • I mazzi sono ciò di cui stiamo parlando qui: oggetti pre-programmati con aspettative che formano una specifica delle chiamate che dovrebbero ricevere.

Stile

Mock vs Stub = test comportamentale vs test di stato

Principio

Secondo il principio del test, solo una cosa per test , ci possono essere diversi stub in un test, ma generalmente c’è solo un mock.

Ciclo vitale

Test del ciclo di vita con stub:

  1. Installazione – Prepara l’object che viene testato e i suoi collaboratori stub.
  2. Esercizio: testare la funzionalità.
  3. Verifica stato: utilizza asserzioni per verificare lo stato dell’object.
  4. Teardown: ripulisci le risorse.

Test del ciclo di vita con mock:

  1. Dati di configurazione: preparare l’object sottoposto a test.
  2. Aspettative di impostazione – Preparare aspettative in simulazione che viene utilizzata dall’object primario.
  3. Esercizio: testare la funzionalità.
  4. Verifica le aspettative : verifica che i metodi corretti siano stati richiamati in simulazione.
  5. Verifica stato: utilizza asserzioni per verificare lo stato dell’object.
  6. Teardown: ripulisci le risorse.

Sommario

Entrambi i test sui mock e sugli stub danno una risposta alla domanda: qual è il risultato?

Anche i test con i mock sono interessati a: come è stato ottenuto il risultato?

Stub è semplice object falso. Semplicemente assicura che il test funzioni senza intoppi.
Mock è un mozzicone più intelligente. Si verifica che il test passi attraverso di esso.

Ecco una descrizione di ognuno seguito da un campione del mondo reale.

  • Fittizio : solo valori fasulli per soddisfare l’ API .

    Esempio : se stai testando un metodo di una class che richiede molti parametri obbligatori in un costruttore che non hanno alcun effetto sul test, puoi creare oggetti fittizi allo scopo di creare nuove istanze di una class.

  • Fake : crea un’implementazione di test di una class che può avere una dipendenza da qualche infrastruttura esterna. (È buona norma che il test dell’unità NON interagisca effettivamente con l’infrastruttura esterna).

    Esempio : creare un’implementazione falsa per accedere a un database, sostituirlo con in-memory raccolta in in-memory .

  • Stub – sovrascrivi i metodi per restituire valori hardcoded, detti anche state-based sullo state-based .

    Esempio : la tua class di test dipende da un metodo Calculate() richiede 5 minuti per essere completato. Anziché attendere 5 minuti, è ansible sostituire la sua implementazione reale con stub che restituisce valori codificati; prendendo solo una piccola frazione del tempo.

  • Mock – molto simile a Stub ma interaction-based piuttosto che sullo stato. Ciò significa che non ti aspetti da Mock di restituire un valore, ma di assumere che sia stato creato un ordine specifico di chiamate al metodo.

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

Mocks e Mocks sono in realtà sottotipi di Mock , entrambi implementano l’implementazione reale con l’implementazione del test, ma per motivi diversi e specifici.

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

mozzicone

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

finto

Uno stub con un’affermazione secondo cui il metodo viene chiamato.

Così come Sean Copenhaver ha descritto nella sua risposta, la differenza è che i mock definiscono le aspettative (cioè affermano, se e come vengono chiamati).

Gli stub non falliscono i test, può fare finta.

Penso che la risposta più semplice e chiara a questa domanda sia stata 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. L’asserisce che gli usi del test sono sempre contrari alla class in esame.

D’altra parte, il test utilizzerà un object fittizio per verificare se il test è fallito o meno. […]

Ancora una volta, l’object mock è l’object che usiamo per vedere se il test è fallito o meno.

Ciò significa che se stai facendo affermazioni contro il falso significa che stai usando il falso come una finta, se stai usando il falso solo per eseguire il test senza asserzione su di esso stai usando il falso come uno stub.

Penso che la differenza più importante tra loro sia la loro intenzione.

Lasciatemi provare a spiegarlo in WHY stub vs. WHY mock

Supponiamo che io stia scrivendo un codice di test per il controllore della timeline pubblica del mio mac twitter client

Ecco il codice di esempio del test

 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 il mio test lento. So che restituirà le timeline, quindi ho creato uno stub che simula l’API HTTP di Twitter, in modo che il test possa essere eseguito molto velocemente e posso eseguire il test anche se sono offline.
  • MOCK: Non ho ancora scritto nessuno dei miei metodi UI, e non sono sicuro di quali metodi ho bisogno di scrivere per il mio object ui. Spero di sapere come il mio controller collaborerà con il mio object ui scrivendo il codice di test.

Scrivendo mock, si scopre la relazione di collaborazione degli oggetti verificando che le aspettative sono soddisfatte, mentre lo stub simula solo il comportamento dell’object.

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

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

Cosa intendi per Apple?

Se lo si confronta con il debug:

Stub è come assicurarsi che un metodo restituisca il valore corretto

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

Per essere molto chiari e pratici:

Stub: una class o un object che implementa i metodi della class / object da simulare e restituisce sempre ciò che desideri.

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, così puoi essere sicuro che qualche implementazione sta chiamando quel metodo.

Come dice @mLevan, immagina come un esempio che stai testando una class 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!'); } } 

Mi piace la spiegazione di Roy Osherove [collegamento video] .

Ogni class o object creato è un falso. È una simulazione se si verificano le chiamate contro di essa. Altrimenti è un mozzicone.

Leggendo tutte le spiegazioni di cui sopra, lasciami provare a condensare:

  • Stub : un pezzo di codice fittizio che consente di eseguire il test, ma non ti interessa cosa gli succede.
  • Mock : un pezzo di codice fittizio, che VERIFY è chiamato correttamente come parte del test.
  • Spy : un pezzo di codice fittizio, che intercetta alcune chiamate a un vero pezzo di codice, permettendoti di verificare le chiamate senza sostituire l’intero object originale.

Un falso è un termine generico che può essere utilizzato per descrivere uno stub o un object fittizio (scritto a mano o in altro modo), perché entrambi assomigliano all’object reale.

Se un falso è uno stub o una simulazione dipende da come viene utilizzato nel test corrente. Se è usato per controllare un’interazione (asserita contro), è un object fittizio. Altrimenti, è uno stub.

Fakes assicura che il test funzioni senza intoppi. Significa che il lettore del tuo test futuro capirà quale sarà il comportamento dell’object falso, senza bisogno di leggere il suo codice sorgente (senza bisogno di dipendere da risorse esterne).

Che cosa significa test senza intoppi?
Forexample nel seguente codice:

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

Se vuoi testare il metodo mailService.SendEMail () , per farlo devi simulare un'eccezione nel tuo metodo di test, quindi devi solo creare una class errorServer di Fake Stub per simulare quel risultato, quindi il codice di test sarà in grado di testare metodo mailService.SendEMail (). Come puoi vedere, devi simulare un risultato proveniente da un'altra class ErrorService di dipendenza esterna.

Questa slide spiega molto bene le principali differenze.

inserisci la descrizione dell'immagine qui

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

Proprio dai paper Mock Roles, non Objects , dagli sviluppatori di jMock:

Gli stub sono implementazioni fittizie del codice di produzione che restituiscono risultati in scatola. I Mock Objects fungono da stub, ma includono anche asserzioni per strumentare le interazioni dell’object target con i suoi vicini.

Quindi, le principali differenze sono:

  • le aspettative impostate sugli stub sono generalmente generiche, mentre le aspettative impostate sui mock possono essere più “intelligenti” (es. restituirle alla prima chiamata, questa al secondo ecc.).
  • gli stub vengono utilizzati principalmente per impostare gli input indiretti del SUT , mentre i mock possono essere utilizzati per testare sia gli input indiretti che le uscite indirette del SUT.

Per riassumere, cercando anche di disperdere la confusione dal titolo dell’articolo di Fowler : i mock sono stub, ma non sono solo stub .

  • Stubs vs. Mock
    • stubs
      1. fornire risposte specifiche ai metodi di chiamata
        • ex: myStubbedService.getValues ​​() restituisce solo una stringa richiesta dal codice sotto test
      2. usato dal codice sotto test per isolarlo
      3. non può fallire il test
        • ex: myStubbedService.getValues ​​() restituisce solo il valore di stub
      4. spesso implementano metodi astratti
    • Mocks
      1. “superset” di stub; può affermare che determinati metodi sono chiamati
        • ex: verifica che myMockedService.getValues ​​() venga chiamato una sola volta
      2. usato per testare il comportamento del codice sotto test
      3. può fallire il test
        • ex: 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

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

 namespace UnitTestProject2 { using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; [TestClass] public class UnitTest1 { ///  /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero ///  [TestMethod] public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce() { // Arrange var mockEntityRepository = new Mock(); mockEntityRepository.Setup(m => m.GetName(It.IsAny())); var entity = new EntityClass(mockEntityRepository.Object); // Act var name = entity.GetNameWithPrefix(12); // Assert mockEntityRepository.Verify(m => m.GetName(It.IsAny()), Times.Once); } ///  /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero ///  [TestMethod] public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled() { // Arrange var mockEntityRepository = new Mock(); mockEntityRepository.Setup(m => m.GetName(It.IsAny())); var entity = new EntityClass(mockEntityRepository.Object); // Act var name = entity.GetNameWithPrefix(0); // Assert mockEntityRepository.Verify(m => m.GetName(It.IsAny()), Times.Never); } ///  /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix ///  [TestMethod] public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix() { // Arrange var stubEntityRepository = new Mock(); stubEntityRepository.Setup(m => m.GetName(It.IsAny())) .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"; } } } 

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

Lo stub ci aiuta a eseguire il test. Come? Fornisce valori che aiutano a eseguire 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 ai valori nella tabella del database. Quindi, invece di interagire direttamente con il database, interagiamo con Hashmap.

Mock è un object falso che esegue il test. dove mettiamo l’assert.

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

Stub – Lo stub è una tecnica di sviluppo del software utilizzata per implementare i metodi delle classi all’inizio del ciclo di vita dello sviluppo. Vengono comunemente utilizzati come segnaposto per l’implementazione di un’interfaccia nota, in cui l’interfaccia è finalizzata o nota ma l’implementazione non è ancora nota o finalizzata. Si inizia con gli stub, il che significa semplicemente che si scrive solo la definizione di una funzione e si lascia il codice effettivo per dopo. Il vantaggio è che non dimenticherai i metodi e puoi continuare a pensare al tuo design mentre lo vedi in codice. È anche ansible fare in modo che lo 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 hai inserito, riceverai 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" 

Gli oggetti fittizi sono usati nei casi di test di simulazione che convalidano che determinati metodi sono chiamati su quegli oggetti. Gli oggetti simulati sono oggetti simulati che imitano il comportamento degli oggetti reali in modi controllati. Generalmente si crea un object fittizio per testare il comportamento di qualche altro object. I mazzi ci consentono di simulare risorse non 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 asserisce il parametro con il quale è stato chiamato. Puoi usare il mock con oggetti non solo le funzioni come mostrato qui, e puoi anche restituire un valore in modo che un object mock possa essere usato per sostituire uno stub per il test.

Altro su unittest.mock , si noti in Python 2.x mock non è incluso 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 bello se un libro simile fosse stato scritto usando gli esempi Python e Python. Se qualcuno sa di un libro, per favore, condividilo. Saluti 🙂

Uno stub è un object falso costruito a scopo di test. Un finto è uno stub che registra se le chiamate previste si sono effettivamente verificate.

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 asserzioni e stato:

  • I mock sono fatti valere prima di un evento o di un cambiamento di stato
  • Gli stub non sono asseriti, forniscono lo stato prima di un evento per evitare l’esecuzione di codice da unità non correlate
  • Le spie sono configurate come stub, quindi fatte valere dopo un evento o un cambiamento di stato
  • I falsi non sono asseriti, corrono dopo un evento con dipendenze hardcoded per evitare lo stato

Riferimenti

  • Geek Glossary: ​​Mock
  • Glossario Geek: Stub
  • Glossario Geek: spia
  • Test doppio: falsi, derisioni e tronconi

un sacco di risposte valide lassù ma penso che valga la pena menzionare questo modulo zio bob: https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html

la migliore spiegazione di sempre con esempi!

Uno stub è un object che implementa un’interfaccia di un componente, ma invece di restituire ciò che il componente restituisce quando chiamato, lo stub può essere configurato per restituire un valore adatto al test. Usando gli stub un test di unità può verificare se un’unità può gestire vari valori di ritorno dal suo collaboratore. L’utilizzo di uno stub anziché di un vero collaboratore in un test di unità potrebbe essere express in questo modo:

unit test -> stub

unit test -> unit -> stub

il test dell’unità asserisce sui risultati e sullo stato dell’unità

Prima il test unitario crea lo stub e configura i suoi valori di ritorno. Quindi il test unitario crea l’unità e imposta lo stub su di esso. Ora il test dell’unità chiama l’unità che a sua volta chiama lo stub. Infine, il test unitario fa affermazioni sui risultati delle chiamate di metodo sull’unità.

Un Mock è come uno stub, solo ha anche metodi che permettono di determinare quali metodi sono stati chiamati sul Mock . Utilizzando una simulazione è quindi ansible testare se l’unità è in grado di gestire correttamente vari valori di ritorno, e anche se l’unità utilizza correttamente il collaboratore. Ad esempio, non è ansible vedere dal valore restituito da un object dao se i dati sono stati letti dal database utilizzando un’istruzione o un PreparedStatement. Né puoi vedere se il metodo connection.close () è stato chiamato prima di restituire il valore. Questo è ansible con i mock. In altre parole, mock permette di testare un’interazione completa di unità con un collaboratore. Non solo i metodi collaboratore che restituiscono i valori utilizzati dall’unità. L’utilizzo di una simulazione in un test di unità potrebbe essere express in questo modo:

unit test -> mock

unit test -> unit -> mock

il test dell’unità asserisce sul risultato e sullo stato dell’unità

il test unitario asserisce sui metodi chiamati simulati

Maggiori dettagli >> qui

Punto di vista del test Stub and Mock:

  • Lo stub è un’implementazione fittizia eseguita dall’utente in modo statico , vale a dire in Stub che scrive il codice di implementazione. Quindi non può gestire la definizione del servizio e le condizioni dinamiche, Normalmente questo viene fatto nel framework JUnit senza usare il framework di simulazione.

  • Mock è anche un’implementazione fittizia, ma la sua implementazione è stata eseguita in modo dinamico utilizzando framework Mocking come Mockito. In questo modo possiamo gestire la definizione di condizioni e servizi come modo dinamico, ovvero i mock possono essere creati dynamicmente dal codice in fase di runtime. Quindi usando simulazioni possiamo implementare Stub in modo dinamico.

seguendo è la mia comprensione …

  • se crei oggetti test localmente e fornisci il tuo servizio locale con quello, stai usando l’object mock. questo darà un test per il metodo che hai implementato nel tuo servizio locale. è usato per verificare i comportamenti

  • quando si ottengono i dati di test dal fornitore di servizi reali, anche se da una versione di prova dell’interfaccia e si ottiene una versione di prova dell’object, si sta lavorando con stub lo stub può avere la logica per accettare determinati input e fornire un output corrispondente per aiutarti a eseguire verifica dello stato …

Gli stub vengono utilizzati su metodi con un valore di ritorno previsto che è stato impostato nel test. I mock sono usati sui metodi void che sono verificati nell’Assert che sono chiamati.

Mock – Un mock intercetta una chiamata a un metodo o funzione (o un gruppo di metodi e funzioni come nel caso di una class derisa). Non è un’alternativa a quel metodo o funzione. In quell’intercettazione, la simulazione può fare tutto ciò che vuole, come registrare l’input e l’output, decidere di cortocircuitare la chiamata, cambiare il valore restituito, ecc.

Stub – Uno stub è un’implementazione valida e pienamente funzionante di un metodo o funzione (o un gruppo di metodi e funzioni come nel caso di una class stub) che ha un’interfaccia / firma identica al metodo, alla funzione o al gruppo di metodi e funzioni per lo stub. L’implementazione stub in genere eseguirà solo le cose che sono accettabili nel contesto di un test unitario, il che significa che non eseguirà l’IO ad esempio, mentre imita il comportamento della cosa che sta eseguendo lo stub.

vediamo Test doppio:

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

  • Mock : i mock sono oggetti che registrano le chiamate che ricevono. In asserzione di test, possiamo verificare su Mock che sono state eseguite tutte le azioni previste. Ad esempio : una funzionalità che chiama il servizio di invio e-mail. per altro basta controllare questo .