2009-05-13 14 views
5

He visto muchos métodos locos para acceder a variables privadas cuando se prueban las unidades. Lo más alucinante que he visto es #define private public.Pruebas unitarias con -fno-access-control

Sin embargo, nunca he visto a nadie que sugiera desactivar las variables privadas en el nivel del compilador. Siempre había supuesto que no podrías. Me he quejado a muchos desarrolladores de que las pruebas unitarias serían mucho más sencillas si pudieras decirle al compilador que retroceda para este único archivo.

Luego tropiezo con la opción del compilador gcc -fno-access-control. Es obviamente la manera perfecta de probar la unidad. Tus archivos fuente originales no han sido modificados, no hay amigos inyectados solo para la prueba de la unidad, no se recompila con la extraña magia del preprocesador. Simplemente haga clic en el interruptor 'no access control' cuando compile las pruebas de su unidad.

¿Echo de menos algo? ¿Es esta la unidad que prueba la bala de plata? Espero que sea?

La única desventaja que veo es la naturaleza específica de gcc de la técnica. Sin embargo, supongo que MSVS tiene una bandera similar.

+0

¿Has probado esta técnica? ¿Funciona de hecho? – UncleZeiv

+0

Recopilé un caso de prueba simple antes de publicar la pregunta. De hecho, funciona No lo he probado con ningún proyecto de la vida real o grande, pero supongo que se adapta perfectamente. –

+0

'-fno-access-control' no funciona con herencia privada/protegida. Estoy atascado con '# define's. – Xeverous

Respuesta

6

Yo diría que las pruebas unitarias no deberían tener acceso a los miembros privados.

En general, las pruebas unitarias están destinadas a probar la interfaz a sus clases, no a la implementación interna. De esta forma, los cambios en las partes internas solo romperán las pruebas si la interfaz se ha visto comprometida.

Eche un vistazo a mi answer a una pregunta similar, y la discusión posterior. Es un tema controvertido, sin duda, pero ese es mi $ 0.02.

-2

Yeap, bastante útil opción GCC, pero MSVC no tiene nada como eso.
Utilizamos macroses lugar:

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

^_^

+0

'#define clase struct' explota en' plantilla ' – Xeverous

2

Normalmente trato de usar solo la interfaz pública de mis clases en pruebas unitarias. El desarrollo/diseño impulsado por prueba ayuda mucho aquí ya que las clases resultantes tienden a permitir este estilo de prueba unitaria.

Sin embargo, a veces es necesario permitir que una unidad de prueba acceda a miembros no públicos, por ejemplo, reemplazar el contenido de un Singleton con una instancia falsa. Para esto utilizo protección de paquetes en Java y amigos en C++.

Algunas personas parecen hacer todo lo posible para evitar amigos, pero se deben utilizar cuando corresponda y su uso no compromete el diseño. También son declarativos y permiten que otros programadores sepan lo que estás haciendo.

1

Wow esto funcionó perfectamente para mí.

Me preocupaba que no fuera así ya que mis unittests necesitan acceder a miembros privados de las clases creadas en otras bibliotecas dinámicas (archivos .so), pero es justo lo que necesito.

Solo necesito declarar el indicador en mi unidad de prueba .so compila (cada prueba es .so). Ni siquiera en las bibliotecas donde se definen los objetos a los que se accede.

Lo necesitaba para acceder a widgets internos en un formulario para completar sus valores; no son visibles para el resto del programa, pero se necesitan si mis pruebas representan al usuario que ingresa la información.Sólo pensé en compartir un caso de uso para aquellas personas negativas de acceso privado :)

También está completo, aquí está mi clase de formulario, que muestra el campo name_ privada:

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); 
}; 

y aquí está el comienzo de mi unidad prueba de acceso a ese 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); 
}