2009-05-13 11 views
5

Ich habe viele verrückte Methoden gesehen, um Zugriff auf private Variablen beim Komponententest zu erhalten. Das überwältigendste was ich gesehen habe ist #define private public.Komponententests mit -fno-access-control

Allerdings habe ich noch nie jemanden gesehen, der vorschlägt, private Variablen auf der Compiler-Ebene auszuschalten. Ich hatte immer angenommen, dass du das nicht kannst. Ich habe mich bei vielen Entwicklern beschwert, dass das Testen von Einheiten viel einfacher wäre, wenn Sie dem Compiler nur sagen könnten, dass er sich für diese eine Datei zurückziehen soll.

Dann stolpere ich über die GNC-Compiler-Option-fno-access-control. Es ist so offensichtlich der perfekte Weg zum Komponententest. Deine originalen Quelldateien sind unmodifiziert, keine injizierten Freunde nur für den Komponententest, kein Neukompilieren mit bizarrer Präprozessormagie. Fangen Sie einfach mit dem Schalter 'keine Zugangskontrolle' an, wenn Sie Ihre Komponententests kompilieren.

Fehle ich etwas? Ist das die Einheit, die Silberkugel testet, hoffe ich es ist?

Der einzige Nachteil, den ich sehe, ist die gcc-spezifische Art der Technik. Ich vermute jedoch, MSVS hat eine ähnliche Flagge.

+0

Haben Sie diese Technik ausprobiert? Funktioniert es tatsächlich? – UncleZeiv

+0

Ich habe vor dem Stellen der Frage einen einfachen Testfall zusammengestellt. Es funktioniert tatsächlich. Ich habe es nicht mit irgendeinem wirklichen Leben oder einem großen Projekt versucht, aber ich nehme an, dass es perfekt skaliert. –

+0

'-fno-access-control' funktioniert nicht mit privater/geschützter Vererbung. Ich stecke fest mit '# define's. – Xeverous

Antwort

6

Ich würde die Unit-Tests argumentieren sollten private Mitglieder keinen Zugang benötigen.

Im Allgemeinen sind Komponententests dazu gedacht, die Schnittstelle zu Ihren Klassen zu testen, nicht die interne Implementierung. Auf diese Weise werden Änderungen an den Interna nur die Tests unterbrechen, wenn die Schnittstelle kompromittiert wurde.

Werfen Sie einen Blick auf meine answer zu einer ähnlichen Frage, und die anschließende Diskussion. Es ist zwar ein kontroverses Thema, aber das sind meine 0,02 $.

-2

Yeap, eher hilfreich GCC-Option, aber MSVC hat nichts dergleichen.
Wir verwenden macroses statt:

#define class struct 
#define private public 
#define protected public 

^_^

+0

'#define class struct' explodiert auf' template ' – Xeverous

2

Normalerweise versuche ich nur die öffentliche Schnittstelle meiner Klassen in Komponententests zu verwenden. Test Driven Development/Design hilft hier sehr, da die resultierenden Klassen dazu neigen, diese Art von Komponententest zu ermöglichen.

Manchmal müssen Sie jedoch einen Unit-Test den Zugriff auf nicht öffentliche Member zulassen, z. B. den Inhalt eines Singleton durch eine Fake-Instanz ersetzen. Dazu benutze ich Paketschutz in Java und Freunde in C++.

Einige Leute scheinen sich nach hinten zu beugen, um Freunde zu vermeiden, aber sie sollten verwendet werden, wenn es angebracht ist und ihre Verwendung das Design nicht beeinträchtigt. Sie sind auch deklarativ und lassen andere Programmierer wissen, was Sie tun.

1

Wow das funktionierte perfekt für mich.

Ich war besorgt es würde nicht als meine Unittests müssen auf private Mitglieder von Klassen in anderen dynamischen Bibliotheken (.so Dateien) gebaut zugreifen, aber es ist genau das, was ich brauche.

Ich muss nur das Flag auf meinem Komponententest deklarieren. So kompiliert (jeder Test ist ein .so). Nicht einmal in den Bibliotheken, in denen die Objekte definiert sind, auf die zugegriffen wird.

Ich brauchte es für den Zugriff auf interne Widgets in einem Formular, um ihre Werte zu füllen; Sie sind für den Rest des Programms nicht sichtbar, werden aber benötigt, wenn meine Tests einen Benutzer darstellen sollen, der die Eingabe eingibt.Ich dachte, ich einen Anwendungsfall für die privaten Zugang Neinsager teilen würde :)

Auch für die Vollständigkeit, hier ist meine Form-Klasse, das private name_ Feld zeigt:

struct EditProduct : public widgets::BusinessObjForm<model::Product> { 
public: 
    EditProduct (WContainerWidget *parent=0); 
protected: 
    void fillObjFields(); 
private: 
    // Consts 
    static const double minPrice = 0.0; 
    static const double maxPrice = 10000.0; 
    // Fields 
    WLineEdit* name_; 
    WTextEdit* description_; 
    WSpinBox* price_; 
    WFileUpload* image_; 
    // Methods 
    bool validate(); 
    void saveProduct(const WString& message); 
}; 

und hier ist der Beginn meiner Einheit Testen Sie den Zugriff auf das Widget:

BOOST_AUTO_TEST_CASE(form_save_test) 
{ 
    EditProduct form(app.root()); 
    string txt = "this is a product"; 
    form.name_->setText(txt); 
    BOOST_CHECK_EQUAL(form.name_->text(), txt); 
} 
Verwandte Themen