2012-03-07 14 views
5

supongamos que tengo varios OrderProcessor s, cada uno de ellos maneja un orden un poco diferente.
La decisión sobre qué OrderProcessor de usar que se hace de acuerdo con las propiedades del objeto Order, y se lleva a cabo por un método de fábrica, así:unidad probando un método de fábrica

public IOrderProcessor CreateOrderProcessor(IOrdersRepository repository, Order order, DiscountPercentages discountPercentages) 
{ 
    if (order.Amount > 5 && order.Unit.Price < 8) 
    { 
     return new DiscountOrderProcessor(repository, order, discountPercentages.FullDiscountPercentage); 
    } 

    if (order.Amount < 5) 
    { 
     // Offer a more modest discount 
     return new DiscountOrderProcessor(repository, order, discountPercentages.ModestDiscountPercentage); 
    } 

    return new OutrageousPriceOrderProcessor(repository, order); 
} 

Ahora, mi problema es que quiero para verificar que la devuelto OrderProcessor ha recibido los parámetros correctos (por ejemplo, el porcentaje de descuento correcto).
Sin embargo, esas propiedades no son públicas en las entidades OrderProcessor.

¿Cómo sugeriría que manejara este escenario?

La única solución que era capaz de llegar a la propiedad está haciendo porcentaje de descuento del OrderProcessor s pública, pero parece una exageración para hacer eso sólo con el propósito de las pruebas unitarias ...

Respuesta

3

Una forma de evitar esto es cambiar los campos que desea probar a internos en lugar de privados y luego establecer los elementos internos del proyecto visibles para el proyecto de prueba. Usted puede leer sobre esto aquí: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

Se podría hacer algo como esto en su archivo AssemblyInfo.cs:

[assembly:InternalsVisibleTo("Orders.Tests")] 

Aunque se podría argumentar que las pruebas unitarias no necesariamente deben preocuparse por los campos privados de usted clase. Tal vez sea mejor pasar los valores al método de fábrica y escribir pruebas de unidad para el resultado esperado cuando algún método (suponiendo que se llame a Calculate() o algo similar) en la interfaz.

O bien, otro enfoque sería probar de forma unitaria los tipos de hormigón (DiscountOrderProcessor, etc.) y confirmar sus valores de retorno a partir de los métodos/propiedades públicos. Luego escriba pruebas unitarias para el método de fábrica que devuelve correctamente el tipo correcto de implementación de la interfaz.

Estos son los enfoques que generalmente tomo cuando escribo un código similar, sin embargo, hay muchas maneras diferentes de abordar un problema como este. Yo recomendaría averiguar dónde obtendría el mayor valor en las pruebas unitarias y escribir de acuerdo con eso.

1

Si el porcentaje de descuento no es público, entonces no es parte del contrato IOrderProcessor y, por lo tanto, no necesita verificación. Solo tiene un conjunto de pruebas unitarias para el Procesador de pedidos de descuento para verificar que está computando correctamente sus descuentos en función del porcentaje de descuento transferido a través del constructor.

+1

Si bien esto está bien y parece razonable querer saber que se usan los porcentajes de descuento correctos, de lo contrario alguien podría cambiar el código para hacer que ambas rutas devuelvan 'discountPercentages.FullDiscountPercentage' y nadie lo sabría, y de repente la gente comenzaría a obtener descuentos completos en lugar del modesto –

+0

Ok, ponga la creación del DiscountOrderProcessor en un método virtual y asegúrese de que se invoque con los parámetros apropiados en función de su lógica de fábrica. – PatrickSteele

+0

Voy a tener que estar de acuerdo con Patrick. Parece que te estás aventurando a pasar de las pruebas unitarias a las pruebas de integración (que también es importante). La prueba unitaria es para una unidad lógica y cada procesador de órdenes debe tener sus propias pruebas unitarias. –

0

Tiene un par de opciones como yo lo veo. puede crear especializaciones de DiscountOrderProcessor:

public class FullDiscountOrderProcessor : DiscountOrderProcessor 
{ 
    public FullDiscountOrderProcessor(IOrdersRepository repository, Order order):base(repository,order,discountPercentages.FullDiscountPercentage) 
    {} 
} 

public class ModestDiscountOrderProcessor : DiscountOrderProcessor 
{ 
    public ModestDiscountOrderProcessor (IOrdersRepository repository, Order order):base(repository,order,discountPercentages.ModestDiscountPercentage) 
    {} 
} 

y comprobar el tipo correcto devuelto.

Podría pasar en una fábrica para crear el DiscountOrderProcessor que solo toma una cantidad, entonces usted podría verificar que esto fue llamado con los parámetros correctos.

Puede proporcionar un método virtual para crear el DiscountOrderProcessor y verificar que se invoque con los parámetros correctos.

Me gusta bastante la primera opción personalmente, pero todos estos enfoques sufren el mismo problema que al final no se puede verificar el valor real y que alguien podría cambiar los montos de descuento y no lo sabría. Incluso en el primer acercamiento terminaría no pudiendo probar cuál era el valor aplicado a FullDiscountOrderProcessor.

Es necesario tener alguna manera de comprobar los valores reales que le deja con:

se podría hacer pública las propiedades (o interna - con ayuda de InternalsVisibleTo) para que pueda interrogar a ellos.

puede tomar el objeto devuelto y comprobar que aplica correctamente el descuento a algún objeto que pase a él.

Personalmente, me gustaría hacer las propiedades internas, pero depende de cómo interactúan los objetos y si pasar un objeto de simulacro al procesador de orden de descuento y verificar que se actúa correctamente es simple, entonces esto podría ser una mejor solución.

Cuestiones relacionadas