Come fan di tipi regolari e semantica dei valori , mi piace che le classi diventino più regolari e non siano polimorfiche. Come fan delle operazioni di non-lancio, sono appassionato di operazioni che sono noexcept
. Apprezzo anche la conferma di quali funzioni membro speciali vengono effettivamente generate dal compilatore. E mi piacerebbe tenere traccia di queste cose insieme al codice a cui sono associate.
C ++ offre il <type_traits>
file di intestazione che offre classi per il controllo di qualità come queste e I ' mi sono divertito a usarli in codice di test unitario come il seguente:
TEST(MyClass, Traits)
{
EXPECT_TRUE(std::is_constructible< MyClass >::value);
EXPECT_TRUE(std::is_nothrow_constructible< MyClass >::value);
EXPECT_FALSE(std::is_trivially_constructible< MyClass >::value);
EXPECT_TRUE(std::is_copy_constructible< MyClass >::value);
EXPECT_TRUE(std::is_nothrow_copy_constructible< MyClass >::value);
EXPECT_FALSE(std::is_trivially_copy_constructible< MyClass >::value);
EXPECT_TRUE(std::is_move_constructible< MyClass >::value);
EXPECT_TRUE(std::is_nothrow_move_constructible< MyClass >::value);
EXPECT_FALSE(std::is_trivially_move_constructible< MyClass >::value);
EXPECT_TRUE(std::is_copy_assignable< MyClass >::value);
EXPECT_TRUE(std::is_nothrow_copy_assignable< MyClass >::value);
EXPECT_FALSE(std::is_trivially_copy_assignable< MyClass >::value);
EXPECT_TRUE(std::is_move_assignable< MyClass >::value);
EXPECT_TRUE(std::is_nothrow_move_assignable< MyClass >::value);
EXPECT_FALSE(std::is_trivially_move_assignable< MyClass >::value);
EXPECT_TRUE(std::is_destructible< MyClass >::value);
EXPECT_TRUE(std::is_nothrow_destructible< MyClass >::value);
EXPECT_FALSE(std::is_trivially_destructible< MyClass >::value);
EXPECT_TRUE(!std::is_polymorphic< MyClass >::value);
}
Come codice di test unitario che sta entrando anche nel mio sistema di revisione del codice sorgente, questo ha il vantaggio di tenere traccia di queste qualità insieme al codice impegnato per MyClass
. Mi piace anche ricevere un gamification kick di vedere le classi assumere più di queste qualità - cosa che faccio usando un codice come questo.
Mi chiedo tuttavia: ci sono altri modi per ottenere ciò che forse hanno più benefici senza tanti trabocchetti?
Ecco alcune preoccupazioni che ho su questa tecnica:
- Sono accettabili come test unitari? Sono per me ma lo sono per gli altri? Mentre la definizione di test unitari che Wikipedia fornisce sembra abbastanza soggettiva da consentire a questo di qualificarsi, sono preoccupato qui quanto ampiamente altri d'accordo.
- Sarebbe meglio rintracciare queste qualità altrove come nel codice della classe stessa usando per esempio
static_assert
? Questo è diverso dall'ultima preoccupazione in ora concentrandosi sul fatto che il loro sia un posto migliore (non se altri sviluppatori di software lo accetterebbero come test unitario). Tracciare queste qualità nel codice della classe tramitestatic_assert
anziché in codice test unitario come mostrato, sembra un'elevazione di queste qualità. Per le classi più performanti, questa direzione ha un senso. Riconosco anche una prospettiva che questi dovrebbero invece essere ridotti in importanza forse per essere solo avvisi o messaggi (invece di fallimenti di test o fallimenti di build). - Mancanza di scalabilità. È più un codice standard di quello che deve essere? È un'operazione di copia e incolla semplice per creare test come questo ma non si presta agli aggiornamenti globali. Preferirei astrarre più questo, se possibile, quindi c'era un posto in cui poteva essere aggiornato. Ho preso in considerazione la conversione di questo in una funzione modello che combina questi controlli e ottiene solo il tipo come parametro del modello. Come farebbe a tenere traccia dei valori veri e falsi? Potrebbe generare un report di output, ma sembra complicato analizzare in
EXPECT_*
contesti con numeri di linea locali. Nel frattempo, una funzione macro verrà valutata nel contesto del test unitario, ma una funzione macro a più istruzioni viene comunque visualizzata come tutto su un'unica riga di codice sorgente: la linea da cui viene chiamata la macro. Ho anche considerato di combinare le forme normali,nothrow
etrivially
di questi controlli, in controlli a linea singola che prendono un parametro per indicare quale di questi dovrebbe applicarsi in positivo. Tuttavia, non ho visto nulla di più soddisfacente del modello mostrato.