Quando contrassegnare una funzione come virtuale?

2

Sto cercando di capire il modo idiomatico di codificare. Sto usando gmock per testare i componenti che scrivo. Gmock richiede che i metodi siano virtuali per essere in grado di prendere in giro, ma la classe che sto cercando di prendere in giro ha un metodo non virtuale che mi piacerebbe essere deriso.

Quindi le opzioni sono per contrassegnare i metodi come virtuali o creare un'interfaccia con metodi virtuali puri. Nessuno dei due sembra l'ideale, visto che farei l'uno o l'altro solo per testare il codice. Come viene solitamente affrontato nel mondo C ++?

    
posta broun 07.04.2016 - 07:40
fonte

3 risposte

3

Il tuo design o test è sbagliato.

Invece di fare il mocking usando un framework, prova a creare la tua classe derivata e progetta il tuo test attorno a questa classe "finta". Ti renderai conto che l'idea di prendere in giro metodi non virtuali non ha alcun senso. L'idea dei metodi virtuali è che la classe base vuole alcune funzionalità e si aspetta che i bambini la forniscano. Se la classe base non rende il metodo virtual, significa che non si aspetta che i suoi figli modifichino il comportamento di quel metodo. E come tale è parte integrante della classe e dovrebbe essere testato come tale. Prendere in giro un metodo non virtuale significherebbe che non stai testando l'intero comportamento della classe base.

Una cosa che ti viene in mente, che ti "costringerebbe" a fare questo è che la classe base ha molteplici responsabilità e che dovrebbe essere separata in più classi dove quella non virtuale è in realtà API della classe estratta.

    
risposta data 07.04.2016 - 08:32
fonte
1

Solitamente contrassegni la classe come virtual quando, oltre ad avere una sorta di implementazione (direttamente nella classe che dichiara la funzione stessa o in un figlio che eredita questa classe), vuoi che la dichiarazione stabilisca un contratto, che deve essere soddisfatte dalle implementazioni.

La dichiarazione dice fondamentalmente: Se mi dai questo set di parametri di questi tipi, mi viene garantito di restituire questo tipo di variabile (il tipo return ). Non devi preoccuparti di cosa succede all'interno della funzione stessa, ma puoi essere sicuro che se mi dai dei parametri di questo tipo, puoi essere certo che ti restituirò il tipo di ritorno.

Questa è chiamata astrazione, quando i perni dell'applicazione sono le dichiarazioni che forniscono comportamenti attesi ma non esatti. Le interfacce, o in classi C ++ che non contengono nient'altro che metodi virtuali puri, sono esattamente questo. Definiscono un contratto ma non forniscono l'implementazione.

Se vuoi testare l'unità, ciò che vuoi nel tuo codice è dipendere da nient'altro che virtual funzioni. Puoi farlo definendo una funzione di una classe che fornisce già un comportamento come virtual o estraendo la dichiarazione della funzione a una nuova classe che rappresenta l'interfaccia della funzione (rendendo la dichiarazione pura virtuale), che la classe iniziale erediti da questa classe astratta appena creata e quindi usa questa classe astratta appena creata per tutto il tuo progetto.

    
risposta data 07.04.2016 - 09:09
fonte
0

È possibile utilizzare l'ereditarietà statica e iniettare l'oggetto tramite l'argomento del modello. Quindi, nei test delle unità, iniettare l'oggetto simulato, invece dell'oggetto reale.

Qualcosa del genere:

struct A {
  void doThings() {
  }
};

struct MockA {
  MOCK_METHOD0(doThings, void());
};


template< typename doer >
struct B {
  void foo() {
    a.doThings();
  }

  doer a;
};

Quindi, nella tua applicazione, usa la classe reale:

B< A > b;

e nei test unitari il mock:

B< MockA > b;
    
risposta data 07.04.2016 - 10:40
fonte

Leggi altre domande sui tag