2009-02-12 15 views
9

Tengo una pregunta relacionada con la prueba unitaria. Digamos que tengo varias clases que heredan el comportamiento de una clase principal. No quiero probar todas las clases de niños por este comportamiento. En cambio, probaría la clase para padres. Sin embargo, también debo proporcionar una prueba que demuestre que el comportamiento está disponible en las clases para niños. ¿Crees que algo como Assert.IsTrue (new ChildClass() es ParentClass) tiene sentido?Herencia de prueba de unidad

Respuesta

7

Si está utilizando un marco de pruebas de unidad de estado de la técnica, no entiendo la declaración

no quiero poner a prueba todas las clases hijas para este comportamiento.

las pruebas unitarias (escrito en una instancia de la clase padre) debería funcionar sin cambios si usted les da una instancia de una clase hija, proporcionan que su clase hija no ha anulado algún aspecto de la comportamiento de los padres de una manera que rompe el contrato sobre los métodos heredados. Y eso es exactamente lo que debes probar, ¿no?

Si le preocupa el tiempo que lleva realizar las pruebas, verifique dos veces para asegurarse de que las pruebas estén divididas de manera que pueda ejecutar pruebas selectivamente en función de lo que esté trabajando activamente (pero todavía ejecute el portafolio completo periódicamente para detectar dependencias involuntarias.)

+1

Amen. Esta es una buena razón para probar realmente que la "herencia funciona" (es decir, se ajusta al principio de sustitución de Liskov) en lugar de simplemente verificar que las clases secundarias sean subtipos de la clase principal. – Sol

+0

No es que me preocupe el tiempo que lleva realizar la prueba. Solo quiero escribir el número mínimo de pruebas posibles para facilitar el rafactoring en el futuro. – trendl

+0

@trendl - Si usa NUnit, puede crear una prueba unitaria para la clase base y usar el atributo [TestCase] ​​para alimentar todas las clases secundarias que tenga, esto le da un control según lo sugerido por Joel para todas sus subclases para gratis. – chiccodoro

8

Creo que escribir una prueba de que la herencia funciona es una pérdida de tiempo. El compilador verificará que los métodos de la clase base estén disponibles si intenta usarlos, suponiendo que no capta con intellisense. Probablemente probaría el comportamiento en una clase de niño y luego solo en cada clase de niño que modifica el comportamiento (o en algún estado del que depende el comportamiento).

5

No querrá probar el tipo de objeto, a menos que proceda de un método de fábrica sin tipo. De lo contrario, estás escribiendo una prueba unitaria contra el compilador C# que no es lo que quieres hacer.

+0

podría argumentar que tener una prueba de que las cadenas de herencia no se han roto es una prueba válida. después de todo, podría tener la clase A que hereda la clase B que hereda la clase C y en algún momento del futuro un dev decide que A apunte directamente a C sería mejor sin darse cuenta de que A depende de una transformación de datos realizada por B – MikeT

1

El compilador de C# se encarga de ese tipo de control para usted.

Si lo desea, puede escribir algo como:

ParentClass childClass = new ChildClass() 
var testOutput = childClass.ParentMethod(); 
Assert.IsNotNull(testOutput); 
0

Hay dos enfoques que puede utilizar para probar el comportamiento de la clase base:

  1. crear una implementación de código auxiliar de la clase base, y la unidad prueba el stub. Solo prueba los métodos públicos. No tiene sentido probar tus métodos privados y protegidos, ya que serán consumidos por métodos públicos que debes probar en tus subclases. Este enfoque no hará cumplir que sus implementaciones de la clase base no han sombreado el comportamiento incorrectamente.
  2. Crear una superclase de prueba para las pruebas de su unidad que ejerce los métodos de clase base. Cada vez que pruebe una subclase de su clase base, haga que su clase de prueba herede de su superclase de prueba. Este enfoque garantiza que no haya cambiado el comportamiento de la clase base inadvertidamente, pero limita la flexibilidad de su prueba.

No se moleste en verificar que la herencia realmente funcione (todo el asunto Assert.IsTrue(new ChildClass() is ParentClass)). Solo debes probar el comportamiento. Esta es una característica estructural del .Net framework (herencia), y debe confiar en que funciona; de lo contrario, se encontrará en una espiral descendente de comprobación de características del framework.

+0

La definición de pruebas unitarias es que prueba el componente más pequeño posible para métodos y propiedades individuales, lo que significa que siempre debe probar sus llamadas secundarias por separado – MikeT

6

haga que sus pruebas hereden de una prueba de clase base, algo [muy] parecido a esto.

public class MyBaseClass 
{ 
    public virtual void DoStuff() { } 
    public virtual void DoOtherStuff() { } 
} 

public class MySubClass : MyBaseClass 
{ 
    public override void DoOtherStuff() 
    { 
     // different to to base 
    } 
} 

public abstract class TestOfBaseClass 
{ 
    protected abstract MyBaseClass classUnderTest { get; } 

    [TestMethod] 
    public void TestDoStuff() 
    { 
     classUnderTest.DoStuff(); 
     Assert.StuffWasDone(); 
    } 
} 

[TestClass] 
public class WhenSubclassDoesStuff : TestOfBaseClass 
{ 
    protected override MyBaseClass classUnderTest 
    { 
     get { return new MySubClass(); } 
    } 

    [TestMethod] 
    public void ShoudDoOtherStuff() 
    { 
     classUnderTest.DoOtherStuff(); 
     Assert.OtherStuffDone(); 
    } 
} 

la mayoría de los marcos de las pruebas populares se ejecutará el método de ensayo en el ensayo de base al ejecutar las pruebas de subclases.

o tal vez echar un vistazo a algo así como https://github.com/gregoryyoung/grensesnitt

+0

Esto es exactamente lo que estábamos buscando. Gracias. – PRMan

0

Mi opinión es que su estructura de la prueba debe reflejar su estructura de objetos así que si tienes coche clase que hereda de vehículo Clase

, entonces debería haber Clase TestCar que hereda de Class TestVehicle

Al hacer esto, Test auto hereda automáticamente las pruebas correctas para todas las pruebas de Vehículo, esto significa que si la función se anula en Car, lo más probable es que se rompa probando que es una Prueba Overriden. requerida en coche para apoyar el nuevo comportamiento, si la prueba no se rompe entonces la anulación fue probablemente superflua en el primer lugar

por ejemplo

class Vehicle 
{ 
    public virtual bool LicenceRequired 
    { 
     get{throw new NotImplmentedException() 
    } 
} 
class Bicycle:Vehicle 
{ 
    public override bool LicenceRequired 
    { 
     get{return false;} 
    } 
} 
class Car:Vehicle 
{ 
    public override bool LicenceRequired 
    { 
     get{return true;} 
    } 
} 
class TestVehicle 
{ 
    public virtual Void LicenceRequiredTest() 
    { 
     Try 
     { 
      LicenceRequired 
      Assert.Fail(); 
     } 
     Catch(){} 
    } 
} 
class TestBicycle:TestVehicle 
{ 
    public override void LicenceRequiredTest() 
    { 
     Assert.IsFalse(LicenceRequired); 
    } 
} 
class TestCar:TestVehicle 
{ 
    public override void LicenceRequiredTest() 
    { 
     Assert.IsTrue(LicenceRequired); 
    } 
} 

NOTA: herencia sólo se debe utilizar cuando se prueba heredada objetos, no solo porque quiere hacer la misma prueba en 10 objetos no relacionados. si desea hacer eso, sugeriría una clase de ayuda estática