2010-05-12 23 views
10

¿Cuál es la manera recomendada de cubrir las pruebas unitarias de clases/métodos genéricos?Enfoque de prueba unitaria para clases/métodos genéricos

Por ejemplo (refiriéndose a mi código de ejemplo a continuación). ¿Sería un caso tener 2 o 3 veces las pruebas para cubrir la prueba de los métodos con algunos tipos diferentes de clases TKey, TNode? ¿O solo una clase es suficiente?

public class TopologyBase<TKey, TNode, TRelationship> 
    where TNode : NodeBase<TKey>, new() 
    where TRelationship : RelationshipBase<TKey>, new() 

{ 
    // Properties 
    public Dictionary<TKey, NodeBase<TKey>> Nodes { get; private set; } 
    public List<RelationshipBase<TKey>> Relationships { get; private set; } 

    // Constructors 
    protected TopologyBase() 
    { 
     Nodes = new Dictionary<TKey, NodeBase<TKey>>(); 
     Relationships = new List<RelationshipBase<TKey>>(); 
    } 

    // Methods 
    public TNode CreateNode(TKey key) 
    { 
     var node = new TNode {Key = key}; 
     Nodes.Add(node.Key, node); 
     return node; 
    } 

    public void CreateRelationship(NodeBase<TKey> parent, NodeBase<TKey> child) { 
    . 
    . 
    . 
+1

Solo iba a hacer el mismo tipo de pregunta. – Casey

Respuesta

3

Por lo general crear un DummyClass con fines de prueba para pasar como un argumento genérico (en su caso se debe crear la clase 3) y la pongo a prueba la clase (TopologyBase) una vez.

Las pruebas con diferentes tipos genéricos no tienen sentido, ya que el tipo genérico no debe romper la clase ToopologyBase.

+0

Entonces, en lugar de crear una clase genérica de decir Entero, crearía una nueva clase específicamente utilizada para probar la clase genérica. ¿Agregarías alguna funcionalidad a la nueva clase? – Casey

+0

Exactamente. No, la nueva clase debería ser un muñeco que no hace nada. – ema

1

Puede utilizar un marco de burla para verificar la interacción esperada entre su clase y el tipo genérico. Yo uso Rhino Mocks para esto.

1

Para probar la unidad de un tipo de producción abierto, cree un tipo de código de prueba que se derive del tipo abierto; luego pruebe ese tipo.

public class TestingTopologyBase : TopologyBase<KeyType, NodeType, RelationshipType> ... 

En la clase TestingTopologyBase, proporcionan una aplicación de base de todos los métodos abstractos o cualquier otra cosa que es obligatoria.

Estas implementaciones de Prueba [ProductionType] a menudo son lugares excelentes para que el código de prueba de la unidad detecte qué está haciendo realmente el tipo genérico bajo prueba. Por ejemplo, puede almacenar información que luego puede usar el código de prueba de su unidad para inspeccionar lo que sucedió durante la prueba.

Luego, en sus métodos de prueba unitaria, cree instancias de la clase TestingTopologyBase. De esta forma, prueba el tipo genérico de forma aislada de cualquier tipo de producción que se derive de él.

Ejemplo:

[TestClass] 
public class TopologyBaseFixture { 

    [TestMethod] 
    public void SomeTestMethod() { 
     var foo = new TestingTopologyBase(...); 
     ...test foo here 
2

Realmente podría depende de su código, pero hay por lo menos dos cosas en que pensar:

  • privado/público: Si el uso implementación o puede utilizar un día de reflexión o el DLR (directamente o mediante la palabra clave dinámica en C#) para algunas operaciones que debe probar con al menos un tipo que no es visible desde el ensamblado de implementación.
  • ValueType/ReferenceType: La diferencia entre ellos podría necesita ser probado en algunos casos, por ejemplo,
    • Llamando al método de objeto de los tipos de valor, como ToString o iguala siempre es correcta, pero no con referencias, ya que pueden ser nulos .
    • Si usted está haciendo pruebas de rendimiento que podría haber consecuencias para pasar alrededor de los tipos de valor, sobre todo si son grandes (en caso de no ocurre sino entre directrices y la realidad a veces hay un pequeño hueco ...)
0

Mucho depende de sus restricciones genéricas. Si uno o más de los parámetros de tipo requieren una interfaz o restricción de clase base, ahora existe una dependencia en el contrato de interfaz. Dado que la lógica de su clase puede depender parcialmente del comportamiento de la clase que implementa la interfaz, es posible que deba burlarse de la interfaz de varias maneras para ejercer todas sus rutas lógicas.Por ejemplo, si tiene T: IEquatable<T>, necesitará usar un tipo con comportamiento de igualdad significativo, como un int.

Cuestiones relacionadas