Stub: definizione, tipi e utilizzo nel testing

Autore: IT Sectr Pubblicato: 2026-04-10 Tempo di lettura: 9 min

Stub (stub, double di test) — un oggetto di test che restituisce risposte predefinite alle chiamate di metodo anziché un’implementazione reale. Nello sviluppo mobile, gli stub isolano il modulo testato dalle richieste di rete, database e filesystem, consentendo di verificare la logica senza configurazione dell’ambiente. A differenza di mock, stub non verifica il comportamento — fornisce solo dati. Maggiori dettagli nell’articolo di Martin Fowler sui test doubles.

Punti chiave

  • Stub — un double di test che restituisce valori predefiniti sulle chiamate di metodo senza logica
  • Isolamento — gli stub disabilitano le dipendenze reali: API, DB, file, sensori
  • Differenza da Mock — stub non verifica le chiamate, sostituisce solo la risposta
  • Android — MockWebServer (OkHttp) come stub per HTTP, MockK.constantAnswer per Kotlin
  • iOS — OCMock e protocolli Swift con implementazioni di test come stub

Cos’è uno Stub e in cosa differisce dagli altri test doubles?

Stub è un oggetto double di test che sostituisce una dipendenza reale in un test e restituisce valori predefiniti per chiamate specifiche. Il termine è stato introdotto nella classificazione di Gerard Meszaros (2007) nel libro «xUnit Test Patterns». Stub appartiene alla categoria dei test doubles — oggetti che sostituiscono componenti reali durante i test. L’obiettivo principale di uno stub è fornire all’unità testata dati prevedibili, eliminando l’incertezza dei sistemi esterni.

Principio di funzionamento — il test configura lo stub prima dell’esecuzione: «quando il metodo getUsers() viene chiamato, restituisci questa lista di utenti». Stub non contiene logica di business, non verifica l’ordine delle chiamate e non registra la cronologia. Si limita a stare al posto del componente reale e restituire ciò che gli è stato detto. Nel contesto del testing Android, ciò significa: il client OkHttp non effettua una richiesta reale al server, ma riceve una risposta da MockWebServer configurato come stub.

  • Stub — restituisce dati, non verifica chiamate
  • Mock — restituisce dati e verifica comportamento (verify)
  • Fake — implementazione semplificata funzionante con logica reale
  • Spy — avvolge un oggetto reale, registrando le chiamate
  • Dummy — viene passato ma non utilizzato (null, oggetto vuoto)

Quando utilizzare — gli stub sono ottimali per testare il livello UI (ViewModel, Presenter) e la logica di business (UseCase, Interactor), dove è necessario verificare la reazione a dati specifici: lista vuota, server ha restituito errore 500, token scaduto. Qualsiasi caso in cui il test richieda uno stato di input specifico è compito dello stub. Ogni scenario di test ha la propria configurazione di stub, rendendo i test leggibili e prevedibili.

Classificazione dei test doubles secondo Meszaros

Gerard Meszaros (2007) nel libro «xUnit Test Patterns» ha identificato cinque tipi di test doubles: dummy, stub, spy, mock, fake. Ogni tipo risolve il proprio problema. Dummy — viene passato ma non utilizzato. Stub — restituisce dati. Spy — registra chiamate. Mock — verifica comportamento. Fake — contiene logica semplificata. Comprendere questa classificazione aiuta lo sviluppatore a scegliere lo strumento giusto per ogni scenario di test.

Dove vengono usati gli stub nel testing di applicazioni mobili

Stub per richieste di rete

Richieste di rete — lo scenario più comune per l’uso degli stub. L’applicazione effettua chiamate HTTP all’API e il test deve verificare la reazione a diverse risposte: JSON riuscito, errore 401 (non autorizzato), timeout, array vuoto. MockWebServer (OkHttp) su Android e URLProtocol (iOS) agiscono come stub, restituendo risposte HTTP predefinite senza connessione reale al server. Questo accelera i test da secondi a millisecondi.

Database — Room (Android) e CoreData (iOS) hanno varianti in memoria, ma la loro configurazione richiede comunque tempo. Stub al posto del repository restituisce elenchi di Entity preparati senza toccare il DB. Ciò è particolarmente efficace per testare ViewModel, dove è necessario verificare ordinamento, filtraggio o trasformazione dei dati. Il test viene eseguito in millisecondi indipendentemente dal volume di dati.

Servizi di sistema — LocationManager, SensorManager, SharedPreferences richiedono un dispositivo reale o un emulatore. Stub per LocationProvider restituisce coordinate predefinite, per SensorManager — valori fissi dell’accelerometro. Su iOS, l’equivalente è CLLocationManager con un’implementazione di delegato di test. Senza stub, questi test richiedono un dispositivo fisico con condizioni specifiche.

Filesystem e cache — caricamento immagini, caching delle risposte, lavoro con file di configurazione — tutte queste operazioni dipendono dallo stato del disco. Stub per FileManager o ImageCache restituisce successo/errore senza leggere file reali. Ciò elimina falsi fallimenti dei test dovuti a discrepanze di percorsi o diritti di accesso su diverse macchine di sviluppo.

Stub vs Mock vs Fake: differenze principali

Divisione delle responsabilità — tre tipi di test doubles risolvono compiti diversi. Stub: «dammi dati». Mock: «verifica che sono stato chiamato». Fake: «funziono come quello reale, solo più semplice». La differenza è fondamentale per la leggibilità dei test: se un test usa mock dove serve stub, è sovraccarico di chiamate verify non correlate allo scenario testato.

CaratteristicaStubMockFake
ScopoFornire datiVerificare interazioneImplementazione semplificata
LogicaNoNoSì (ma semplificata)
VerificaNoSì (verify)Indiretta (tramite stato)
FlessibilitàBassa — risposte fisseMediaAlta — logica si adatta
VelocitàMassimaAltaMedia
EsempioMockWebServer restituisce JSONMockito.verify(repository).save()InMemoryRepository con HashMap

Regola pratica — se il test verifica quali dati ha ricevuto il componente testato — usa stub. Se il test verifica se il componente ha chiamato il metodo della dipendenza con gli argomenti corretti — usa mock. Se vuoi semplicemente sostituire un DB con una tabella hash — questo è fake. Mescolare i tipi in un singolo test lo rende fragile: quando l’implementazione cambia, dovrai riscrivere sia la logica di stub che quella di verify.

Antipattern: Stub con verify

Stub con verify — un errore comune in cui lo sviluppatore configura uno stub e poi aggiunge verify(stub).method(). Stub per definizione non dovrebbe essere verificato — per questo c’è mock. Se devi verificare che un metodo sia stato chiamato con argomenti specifici, usa Mockito.mock() invece di Mockito.stub(). Questa separazione mantiene chiara l’intenzione del test per gli altri sviluppatori.

Implementazione di stub su Android con MockWebServer e MockK

MockWebServer — una libreria OkHttp per creare stub HTTP su Android e JVM. Avvia un server HTTP locale su una porta specificata che intercetta le richieste del client OkHttp e restituisce risposte predefinite. La configurazione richiede tre righe: creare il server, accodare la risposta, avviarlo. Il test può accodare sequenzialmente più risposte per scenari con paginazione o tentativi.

kotlin
class UserRepositoryTest {

    private val server = MockWebServer()

    fun setup() {
        server.start(8080)
        val client = OkHttpClient.Builder()
            .readTimeout(1, TimeUnit.SECONDS)
            .build()
    }

    fun test_user_list_success() {
        val json = "[{\"id\":1,\"name\":\"Alice\"}]"
        server.enqueue(MockResponse()
            .setBody(json)
            .setResponseCode(200)
        )
        val result = repository.getUsers()
        assertEquals(1, result.size)
    }

    fun teardown() {
        server.shutdown()
    }
}

MockK — un’alternativa a Mockito per Kotlin con supporto di prima classe per coroutine, funzioni di estensione e classi sealed. Gli stub in MockK vengono creati tramite coEvery (per funzioni suspend) e every (per funzioni regolari). A differenza di MockWebServer, MockK stub singoli metodi di dipendenza anziché l’intero livello HTTP. Ciò è comodo per i test unitari di UseCase o Interactor, dove le dipendenze sono astrazioni di repository.

kotlin
interface UserRepository {
    suspend fun getUsers(): List<User>
}

class GetUsersUseCaseTest {

    private val repo = mockk<UserRepository>()

    private val useCase = GetUsersUseCase(repo)

    fun test_empty_list() = runTest {
        coEvery { repo.getUsers() } returns emptyList()

        val result = useCase.invoke()

        assertTrue(result.isEmpty())
        coVerify(exactly = 1) { repo.getUsers() }
    }
}

Best practice — per i test di integrazione usa MockWebServer (intercetta HTTP reale), per i test unitari usa MockK (stub interfacce). Non stubbare ciò che non stai testando: se il test verifica il Repository, non stubbare il client OkHttp al suo interno — usa un vero MockWebServer a livello HTTP. Questa regola mantiene i test pertinenti e riduce la fragilità durante il refactoring.

Implementazione di stub su iOS con OCMock e protocolli

Protocolli Swift come stub — nell’approccio nativo iOS, lo stub viene implementato sostituendo una struttura di test che è conforme al protocollo della dipendenza. Invece di un NetworkService reale, il test riceve un StubNetworkService che restituisce dati fissi. Swift è un linguaggio a tipizzazione statica, quindi lo stub deve essere conforme allo stesso protocollo del servizio reale. Il compilatore garantisce che lo stub implementi tutti i metodi richiesti.

swift
protocol NetworkServiceProtocol {
    func fetchUsers() async throws -> [User]
}

struct StubNetworkService: NetworkServiceProtocol {
    let result: Result<[User], Error>

    func fetchUsers() async throws -> [User] {
        try result.get()
    }
}

final class UsersViewModelTests: XCTestCase {
    func test_success_state() async {
        let stub = StubNetworkService(
            result: .success([User(name: "Alice")])
        )
        let vm = UsersViewModel(service: stub)
        await vm.load()
        XCTAssertEqual(vm.users.count, 1)
    }
}

OCMock per Objective-C — una libreria per creare stub e mock in progetti iOS legacy. OCMock supporta metodi stub con argomenti e valori di ritorno. I progetti moderni in Swift preferiscono un approccio basato su protocolli con stub manuali — questo dà controllo su ogni metodo e non richiede dipendenze esterne. OCMock rimane un’opzione per progetti dove protocollizzare tutte le dipendenze non è economicamente fattibile.

URLProtocol per stub HTTP — un meccanismo di sistema in iOS per intercettare le richieste di rete tramite una sottoclasse di URLProtocol. Il test registra un URLProtocol personalizzato che intercetta URLSession e restituisce risposte stub. Il vantaggio rispetto agli stub manuali: non è necessario modificare l’architettura dell’app — URLSession rimane reale, ma i dati vengono sostituiti a livello di protocollo. Lo svantaggio: più difficile da debuggare rispetto a un servizio stub esplicito.

Domande frequenti

In cosa Stub differisce da Mock?

Stub restituisce dati predefiniti e non verifica se una chiamata è avvenuta. Mock verifica inoltre che il metodo sia stato chiamato con gli argomenti corretti (verify). Stub risponde alla domanda «cosa restituire», Mock risponde a «la chiamata è stata effettuata?». Usa stub per la verifica dello stato, mock per la verifica dell’interazione.

Quando usare Fake invece di Stub?

Fake è necessario quando il test richiede un’implementazione funzionante (anche se semplificata) — ad esempio, un database in memoria invece di Room. Stub è adatto per scenari singoli con dati predefiniti. Se ripeti lo stesso stub in 10 test — probabilmente hai bisogno di un Fake. Fake riduce la duplicazione perché la logica vive in una singola classe.

Si possono stubbare metodi statici?

Su Android — MockK per oggetti Kotlin (object) supporta mockkObject(), inclusi i metodi statici delle classi Java tramite mockkStatic(). Su iOS — i metodi statici di Swift non possono essere stubbati direttamente; usa protocolli e DI per sostituire una chiamata static con un metodo di istanza di un protocollo. Gli stub statici sono debito tecnico e vanno evitati nel nuovo codice.

Come stubbare richieste di rete su Android?

Usa MockWebServer (OkHttp) — funziona come un server HTTP locale che accoda risposte. Per Retrofit, sostituisci semplicemente l’URL di base con localhost:8080. Per Ktor, usa MockEngine — un meccanismo integrato per sostituire HttpStatement. Entrambi gli approcci funzionano senza internet reale e danno controllo completo su codice di stato, corpo e intestazioni della risposta.

Stub vs Spy — qual è la differenza?

Spy avvolge un oggetto reale e registra le chiamate, mentre Stub sostituisce completamente l’oggetto con risposte fisse. Spy consente l’uso parziale dell’implementazione reale (gli altri metodi funzionano così come sono), mentre stub no. Se devi verificare che un metodo sia stato chiamato ma parte della logica deve essere eseguita — usa spy, non stub.

Riepilogo

  • Stub — un double di test che restituisce risposte predefinite alle chiamate di metodo durante il test
  • Isolamento delle dipendenze — gli stub sostituiscono richieste di rete, DB, servizi di sistema e filesystem
  • Differenza da Mock — stub non verifica le chiamate, restituisce solo dati senza verifica del comportamento
  • Strumenti Android — MockWebServer per HTTP, MockK per interfacce Kotlin con supporto coroutine
  • Strumenti iOS — stub basati su protocolli in Swift, URLProtocol per HTTP, OCMock per Objective-C
  • Non mescolare i ruoli — non aggiungere verify a stub, usa mock per la verifica delle chiamate
  • Stub + MockWebServer — approccio standard per test di integrazione senza server reale

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche