2009-07-14 14 views
21

Aby móc przetestować mój kod C++, zwykle przekażę konstruktorowi klasy testowej jeden lub kilka obiektów, które mogą być "kodem produkcji" lub obiektami fałszywymi/symulowanymi (nazwijmy to te przedmioty wstrzyknięcia). Zrobiłem to albo przezInterfejsy kontra szablony dla wtrysku zależności w C++

  1. Tworzenie interfejsu, który dziedziczy zarówno klasa "kod produkcyjny", jak i klasa fałszywej/fałszywej.
  2. Wykonywanie klasy w ramach testu klasy szablonów, która przyjmuje typy obiektów wtrysku jako parametry szablonu oraz instancje obiektów wtrysku jako parametry do konstruktora.

Niektóre losowe myśli:

  • Dopóki nie mamy pojęcia (C++ 0x), tylko dokumentacja i parametr nazewnictwa będzie podpowiedź co do zapewnienia klasę badanego (przy użyciu szablonów).
  • Nie zawsze jest możliwe, aby stworzyć interfejsy dla starszych kod
  • Interfejs jest w zasadzie tylko stworzony, aby być w stanie zrobić iniekcji zależność
  • W ten sam sposób: Templating klasa badanego odbywa się wyłącznie w celu umożliwienia iniekcji zależność

Jakie są Twoje myśli? Czy istnieją inne rozwiązania tego problemu?

Odpowiedz

4

Myślę, że opcja interfejsu jest lepsza, ale nie trzeba tworzyć wspólnej klasy bazowej tylko do testu. Możesz odziedziczyć swoją próbną klasę z klasy produkcyjnej i zastąpić niezbędne metody. Będziesz musiał jednak uczynić metody wirtualnymi, ale tak działają narzędzia takie jak mockpp, a także umożliwiają nieco zautomatyzowanie tego procesu.

+0

To takie proste, ale naprawdę potężne. Lubię to! –

+4

Dla przypomnienia, ludzie powinni mieć świadomość, że są problemy z metodami wirtualnymi (zobacz idiom Non-Virtual Interface (NVI)). –

+1

Tak, czasami takie podejście może stać w konflikcie z "purystycznym NVI". W wielu przypadkach można pozbyć się kpiny z chronionych funkcji wirtualnych, ale jeśli trzeba kpić z publicznego nie-wirtualnego interfejsu, to nie zaszkodzi on zbytnio, aby stał się publiczny-wirtualny i nadal używa NVI. W tym przypadku traci się pewne kompilowanie najlepszych praktyk, ale nie jest to najlepsza praktyka. –

8

W C++ jest jeszcze jedna opcja - dajesz fałszywe klasy dokładnie takim samym nazwom jak prawdziwe klasy, a łącząc testy jednostek, po prostu łącz je z fałszywymi obiektami/bibliotekami zamiast rzeczywistymi.

+1

Teoretycznie tak. Ale nie sądzę, że byłoby to dobre w praktyce. Na przykład. klasa, którą chcesz sfałszować podczas jednego testu, będzie prawdopodobnie testowana w innym teście. Następnie musisz utworzyć oddzielny projekt (projekt VS np.) Dla każdego zestawu testów lub coś podobnego ... –

+1

Dość dużo tak. Mam po prostu bardzo silną niechęć do znaczących zmian w kodach (takich jak interfejsy i DI wszędzie, nawet jeśli nie mają prawdziwego sensu) wyłącznie w celu uwzględnienia ram testowania.W każdym razie mogę powiedzieć, że ten schemat działa w praktyce (widziałem go z powodzeniem wykorzystywanego w produkcji), mimo że wymaga on więcej kart katalogowych - ale przynajmniej nie znajduje się w samym kodzie! –

+0

Zgadzam się. Będę musiał zbadać, jakie będą tego konsekwencje dla nas. Może trochę magii można zastosować do projektów VS, aby było łatwiej. –

3

szablony będą miały nieco mniejszą wydajnością kary za czas pracy (mniej indirections, mniej połączeń, kolejne optymalizacje inline), ale sprawi, że cierpi na bardzo wysokie kary za czasów kompilacja ...

Myślę, że do tego celu , interfejsy są lepsze (dopóki nie mamy koncepcji w C++ 0x TR1) ... chyba, że ​​nie można zwolnić niektórych "wąskich gardeł". Interfejsy są bardziej dynamiczne i przełączalne w czasie działania.

Pamiętaj, że możesz skonstruować klasę z domyślnymi obiektami wtryskowymi (rzeczywistymi), ale możesz mieć fabryki, które wstrzykują fałszywe na twoich testach ... nawet nie potrzebujesz podklasy.

+1

Czy mógłbyś rozwinąć ostatni akapit? W jaki sposób używałbyś fabryk do wstrzykiwania fałszywych obiektów? –

+0

http://msdn.microsoft.com/en-us/magazine/cc163739.aspx –

+1

Krótko mówiąc: możesz mieć fabrykę singletonów, która tworzy wszystkie wewnętrzne potrzebne obiekty, i możesz zastąpić tę fabrykę taką, która tworzy próbę obiekty w twoich testach –

2

nie wiem, czy to pomoże, ale można mieć konstruktorów Szablon:

struct Class_Under_Test 
{ 
    template <typename Injected> 
    Class_Under_Test() 
    { 
     ... 

    // and even specialize them 
    template <> 
    Class_Under_Test <A_Specific_Injection_Class> 
    { 
     ... 

Tylko ten, który jest faktycznie stosowany dostanie włączone.

Powiązane problemy