Scrivendo codice mockable in C ++

4

Mi sto concentrando sulla scrittura di codice facile da testare in questi giorni e mi rendo conto che la maggior parte delle mie lezioni seguono lo scheletro sottostante:

Alcune classi ObjectManager hanno bisogno di DatabaseRepo , mentre c'è solo un tipo DatabaseRepo in produzione ( OracleRepo ), lo sto ancora implementando con un'interfaccia perché voglio essere in grado di prendere in giro la DatabaseRepo , quindi ho bisogno di usare il polimorfismo. Inietto DatabaseRepo come unique_ptr al costruttore di ObjectManager , per indicare che ObjectManager possiede DatabaseRepo .

Una cosa, ad esempio, che è difettosa qui è che nel test unitario, accedo allo stato di MockRepo dopo che l'ho spostato in ObjectManager . Anche se è sicuro ( ObjectManager ) è ancora vivo, sembra un hack.

Domanda: Usando questo come schema generale per la situazione in cui la classe A ha un oggetto di tipo B , ci sono aspetti di progettazione che potrei migliorare?

class ObjectManager {
  public:
     ObjectManager(std::unique_ptr<DatabaseRepo> initRepo) : repo(initRepo) {

     }

     void process() {
       repo->updateRecords();
     }


  private:
    std::unique_ptr<DatabaseRepo> repo;
};


class DatabaseRepo {
  public:
    virtual void updateRecords = 0;
} 

class OracleRepo : public DatabaseRepo {
  public:
    void updateRecords() overrides {

    }
}

class MockRepo : public DatabaseRepo {
  public:
    void updateRecords() overrides {

    }
}

testObjectManager() {
   std::unique_ptr<DatabaeRepo> mockrepo = 
       std::unique_ptr<DatabseRepo>(new MockRepo);

   ObjectManager om(std::move(mockrepo)); 
   om.process();

   EXPECT_CALLED_ONCE(mockrepo.get()->updateRecords());
}
    
posta user695652 18.03.2017 - 16:42
fonte

2 risposte

3

Sai che il puntatore rimarrà valido fino a quando ObjectManager non viene distrutto, ma vuoi evitare il deferenziamento di uno spostamento da unique_ptr . In questo caso dovrebbe essere OK mantenere il puntatore originale e usarlo:

testObjectManager() {
   DatabaseRepo* mockrepo = new MockRepo;

   ObjectManager om(std::unique_ptr<DatabaseRepo>(mockrepo)); 
   om.process();

   EXPECT_CALLED_ONCE(mockrepo->updateRecords());
}
    
risposta data 18.03.2017 - 18:12
fonte
2

Perché lo passi come std::unique_ptr<> ?

Utilizzerei invece un riferimento non const .

One thing, for example, which is flawed here is that in the unit test, I access the state of the MockRepo after I moved it into the ObjectManager.

Ti assicurerai che il finto vive finché ne hai bisogno, dato che hai il pieno controllo della tua vita da solo.

Il tuo codice sarà anche più semplice, in quanto non è necessario utilizzare new :

testObjectManager() {
   DatabaseRepo mockrepo;

   ObjectManager om(mockrepo);
   om.process();

   EXPECT_CALLED_ONCE(mockrepo.updateRecords());
}
    
risposta data 18.03.2017 - 17:14
fonte

Leggi altre domande sui tag