Come scrivere test unitari per il client di rete?

4

Ho bisogno di scrivere un semplice client http. Potrebbe essere bello avere test unitari per la mia classe. Ma non so come scrivere una classe corretta e verificabile.

Ad esempio, ho un client come questo:

class HTTPClient
{
public:
     HTTPCLient(const std::string& host, const std::string& port): session(host, port) {}

     void send()
     {
         session.sendRequest(someRequest);
         Response response = session.receiveResponse();
         // ...
     }

private:
    SomeLibrary::ClientSession session;
};

Come testare il metodo send (che invio veramente quello che voglio)? Non posso deriderlo. Posso scrivere che HTTPClient riceve SomeLibrary::ClientSession oggetto nel costruttore (nel test passerei il mock) ma è un buon design? Penso che il modo di attuare la sessione ecc. Debba essere nascosto nella mia classe.

Hai qualche idea?

    
posta pawell55555 07.04.2016 - 03:43
fonte

2 risposte

4

Sì, sarebbe un buon progetto per rompere quella dipendenza diretta dall'implementazione della sessione e invece iniettarla. (Non solo per scopi di test.)

template <typename SessionT>
class HTTPClient
{
private:

  SessionT session_ {};

public:

  HTTPClient(SessionT session) : session_ {std::move(session)}
  {
  }

  // Optional convenience overload
  HTTPClient(const std::string& host, const int port) : session_ {host, port}
  {
  }

  void
  send()
  {
    this->session_.sendRequest(someRequest);
    auto response = this->session_.receiveResponse();
    // …
  }

};

Nota l'uso di auto per il tipo di risposta. In alternativa, richiede che SessionT fornisca un% nidificato co_de appropriato.

using ResponseT = typename SessionT::response_type;

Se non vuoi utilizzare typedef s, dovresti definire un'interfaccia template per la tua sessione virtual e usarla tramite puntatori intelligenti. Raccomando di rimanere con class .

Si noti che questa generalizzazione ha uno scopo che va oltre il test unitario. Ad esempio, è possibile provare una libreria diversa, utilizzare HTTPS con diverse implementazioni TLS, connettersi a un server locale tramite socket di dominio UNIX, comunicare con un processo server tramite una coppia di pipe o persino implementare client e server nello stesso processo , comunicando tramite una coda di messaggi. Non tutte queste opzioni possono sembrare rilevanti per te oggi, ma è bene avere la flessibilità.

A proposito, la tua "sessione" non dovrebbe essere una "connessione"?

    
risposta data 07.04.2016 - 04:12
fonte
0

How to test send method (that I really send what I want)? I can't mock it. I can write that HTTPClient receives SomeLibrary::ClientSession object in constructor (in test I would pass mock) but is it good design?

Sì. Dovresti inserire definitivamente la connessione / sessione nel client.

I think that the way of implementing of session etc. should by hidden in my class.

Forse; Se è il caso, dividi HttpClient in tre:

  • una classe di implementazione client, come modello sul tipo di sessione:

    template <typename SessionT>
    class HTTPClientImpl { /* injected session, see @5gon12eder's answer */... };
    
  • un'implementazione di sessione;

  • un client estremamente sottile che mette tutto insieme:

    class HttpClient: private HTTPClientImpl<SessionT> // session type is now
                                                       // an implementation detail,
                                                       // invisible outside of HttpClient
    {
    };
    

    Questa classe non verrebbe testata; Invece, prova la classe di implementazione.

Per quanto riguarda la testablabilità della tua classe, dovresti testarla con una vera connessione di rete e un server fittizio (che serve contenuti codificati). Ecco una implementazione del server HTTP di esempio ; Dovrebbe richiedere meno di un giorno lavorativo per prendere il codice, integrarlo nella build e cambiarlo in un oggetto attivo (che esegue un server in background) che restituisce risposte predefinite. tale oggetto attivo dovrebbe consentire di scrivere più test di unità con varie risposte del server, rapidamente.

In questo modo, otterrai molti errori difficili da simulare o simulare senza il traffico di rete (ad esempio, il groviglio non deterministico di messaggi più grandi in blocchi di dati, a seconda del traffico di rete corrente).

    
risposta data 08.04.2016 - 10:51
fonte

Leggi altre domande sui tag