2009-01-07 20 views
14

Tengo una clase que estoy probando unitariamente con DUnit. Tiene una serie de métodos algunos métodos públicos y métodos privados.¿Cómo puedo probar métodos privados con DUnit?

type 
    TAuth = class(TDataModule) 
    private 
    procedure PrivateMethod; 
    public 
    procedure PublicMethod; 
    end; 

Para escribir una prueba unitaria para esta clase, tengo que hacer que todos los métodos sean públicos.

¿Existe alguna manera diferente de declarar los métodos privados para poder probarlos pero no son públicos?

+0

Vea también: [¿Cuál es la forma correcta de probar una clase con métodos privados utilizando JUnit?] (Http://stackoverflow.com/questions/34571/whats-the-proper-way-to-test-a-class -with-private-methods-using-junit) – mjn

+0

Otra opción http://stackoverflow.com/questions/7525071/accesing-a-strict-private-field-using-the-rtti – sav

+0

Posible duplicado de [¿Cómo puedo probar? una clase que tiene métodos privados, campos o clases internas?] (https://stackoverflow.com/questions/34571/how-do-i-test-a-class-that-has-private-methods-fields-or- inner-classes) – Raedwald

Respuesta

19

No es necesario que sean públicos. Protegido hará. Luego puede subtipificar la clase para las pruebas unitarias y explorar los métodos protegidos. Ejemplo:

type 
    TAuth = class(TDataModule) 
    protected 
    procedure MethodIWantToUnitTest; 
    public 
    procedure PublicMethod; 
    end; 

Ahora puede subtipo para su unidad de prueba:

interface 

uses 
    TestFramework, Classes, AuthDM; 

type 
    // Test methods for class TAuthDM 
    TestAuthDM = class(TTestCase) 
    // stuff 
    end; 

    TAuthDMTester = class(TAuthDM) 
    public 
    procedure MethodIWantToUnitTestMadePublic; 
    end; 

implementation 

procedure TAuthDMTester.MethodIWantToUnitTestMadePublic; 
begin 
    MethodIWantToUnitTest; 
end; 

Sin embargo, si los métodos que desea probar la unidad están haciendo las cosas tan íntimamente con el módulo de datos que no es seguro para tener algo más que privado, entonces realmente debería considerar refactorizar los métodos para segregar el código que necesita ser probado por unidades y el código que accede a las entrañas del módulo de datos.

+2

Sí, sin sonar demasiado negativo No estoy de acuerdo con hacer que sus métodos privados estén protegidos por el bien de las pruebas unitarias, ya que son privados por algún motivo. Creo que deberías probar la interfaz pública. Son los métodos públicos que van a usar sus métodos privados de todos modos. – CodeAndCats

+1

Yo (respetuosamente) no estoy de acuerdo, por razones que detallo aquí: http://blogs.teamb.com/craigstuntz/2009/01/12/37919/ –

+1

/Ben: privado y protegido son diferentes las posibilidades y cada uno tiene sus méritos y desventajas; Si desea probar los métodos privados, protegerlos es simplemente una manera simple de hacerlos accesibles a su marco de prueba (DUnit). ¿Qué sigue: lo privado es malo y lo privado estricto aún más? Estoy de acuerdo con Ben: la prueba unitaria es para probar tu contrato (por ejemplo, la interfaz pública con sus reglas explícitas (interfaz) y explícitas (uso)). Si los miembros privados necesitan pruebas, debe hacer que la interfaz sea formal (parte de una interfaz tal vez, clase interna, etc.). –

4

recomiendo el libro "XUnit Test Patterns" por Gerard Meszaros:

Test-Specific Subclass

Pregunta: ¿Cómo podemos hacer que el código comprobable cuando necesitamos acceder a estado privada de la IVU ?

respuesta: Añadir métodos que exponen el estado o comportamiento que necesita la prueba a una subclase de la IVU.

... Si el sistema bajo prueba (SUT) no era diseñado específicamente para ser comprobable, podemos encontrar que la prueba no puede obtener acceso a Estado que debe inicializar o verificar en algún momento de la prueba.

El artículo también explica cuándo usarlo y qué riesgos conlleva.

4

Ponga el código de DUnit dentro de su unidad. A continuación, puede acceder a cualquier cosa que desee.

+3

... mediante el uso de directivas condicionales solamente – too

7

que es un poco hacky, pero me gusta usar esta directiva de compilación condicional:

{$IfNDef TEST} 
    private 
    {$EndIf} 

Su proyecto de prueba de unidad debe definir PRUEBA en project → conditional defines.

Sin una especificación de visibilidad, se publican. Cuidado: si la visibilidad privada no es la primera en la declaración de clase, obtendrá la definición anterior.Una forma más segura, pero más detallado y menos claro, sería:

private 
    {$IfDef TEST} 
    public 
    {$EndIf} 

Esto tiene algunas ventajas con respecto a la creación de subclases u otros enfoques:

  • ninguna complejidad adicional: no hay clases adicionales en el código
  • Nadie puede subclasificar y anular "erróneamente" su clase: conserva su arquitectura
  • Cuando dice que un método está protegido, de alguna manera espera que se anule. Usted está diciendo esto para quién está leyendo su código. Un método protegido que no debe ser anulado confundirá a los lectores de su código, rompiendo mi primer principio de programación: "el código debe escribirse para ser leído por otros seres humanos".
  • DUnit está en su propia unidad, no se incluye en todas partes
  • No toca el sucio RTTI.

Creo que es una solución más clara y mejor que la respuesta seleccionada.

Cuando uso esto, también configuro el proyecto de prueba para colocar los objetos de compilación en un directorio diferente del proyecto principal. Esto evita que los binarios con la directiva TEST se mezclen con el otro código.

4

En general, cuando llego a esta situación, a menudo me doy cuenta de que estoy violando el principio de responsabilidad única. Por supuesto, no sé nada sobre su caso específico, pero QUIZÁ, que los métodos privados deben ser de su propia clase. El TAuth tendría una referencia a esta nueva clase en su sección privada.

1
{$IFNDEF UNITEST} 
private 
{$ENDIF} 

solución simple, que casi no es un truco. Con frecuencia necesito probar métodos privados y esta técnica agrega la menor complicación posible.

Cuestiones relacionadas