it-swarm-es.tech

¿Cómo sabes qué probar cuando escribes pruebas unitarias?

Usando C #, necesito una clase llamada User que tiene un nombre de usuario, contraseña, marca activa, nombre, apellido, nombre completo, etc.

Debería haber métodos para autenticar y guardar un usuario. ¿Acabo de escribir una prueba para los métodos? ¿Y tengo que preocuparme por probar las propiedades ya que son las que obtienen y configuran .Net?

126
Mike Roosa

Muchas respuestas geniales a esto también están en mi pregunta: " ¿Comenzando TDD - Desafíos? ¿Soluciones? ¿Recomendaciones? "

También puedo recomendar echar un vistazo a mi blog post (que fue en parte inspirado por mi pregunta), tengo algunos comentarios positivos al respecto. A saber:

No sé por dónde empezar?

  • Comenzar de nuevo. Solo piense en escribir pruebas cuando escriba un nuevo código. Esto puede ser un nuevo trabajo de código antiguo, o una característica completamente nueva.
  • Comience simple. No se vaya corriendo y trate de orientarse en torno a un marco de prueba, además de tener la tecnología TDD. Debug.Assert funciona bien. Úsalo como punto de partida. No se mete con tu proyecto ni crea dependencias.
  • Comience positivo. Estás tratando de mejorar tu oficio, siéntete bien al respecto. He visto un montón de desarrolladores que están felices de estancarse y no probar cosas nuevas para mejorar su situación. Estás haciendo lo correcto, recuerda esto y te ayudará a evitar que te rindas.
  • Comience listo para un desafío. Es bastante difícil empezar a hacer pruebas. Espere un desafío, pero recuerde que los desafíos pueden superarse.

Solo prueba para lo que esperas

Tuve problemas reales cuando comencé porque estaba constantemente sentado allí tratando de descubrir todos los problemas posibles que podrían surgir y luego tratar de probarlo y solucionarlo. Esta es una forma rápida de un dolor de cabeza. Las pruebas deben ser un verdadero proceso YAGNI. Si sabes que hay un problema, escribe una prueba para él. De lo contrario, no te molestes.

Solo prueba una cosa

Cada caso de prueba solo debería probar una cosa. Si alguna vez encuentra "y" en el nombre del caso de prueba, está haciendo algo mal.

Espero que esto signifique que podamos pasar de "buscadores y creadores" :)

130
Rob Cooper

Prueba tu código, no el idioma.

Una prueba unitaria como:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

solo es útil si está escribiendo un compilador y existe una posibilidad distinta de cero de que su método instanceof no esté funcionando.

No pruebe cosas en las que pueda confiar el lenguaje para hacer cumplir. En su caso, me concentraría en sus métodos de autenticación y guardado, y escribía pruebas que me aseguraran de que pudieran manejar valores nulos en cualquiera o en todos esos campos con gracia.

62
Tim Howland

Esto me puso en pruebas de unidad y me hizo muy feliz

Acabamos de empezar a hacer pruebas unitarias. Durante mucho tiempo supe que sería bueno comenzar a hacerlo, pero no tenía idea de cómo empezar y, lo que es más importante, qué probar.

Luego tuvimos que reescribir un código importante en nuestro programa de contabilidad. Esta parte era muy compleja ya que involucraba muchos escenarios diferentes. La parte de la que estoy hablando es un método para pagar las ventas y/o comprar facturas ya ingresadas en el sistema contable.

Simplemente no sabía cómo empezar a codificarlo, ya que había tantas opciones de pago diferentes. Una factura podría ser de $ 100, pero el cliente solo transfirió $ 99. Tal vez usted haya enviado facturas de ventas a un cliente, pero también ha comprado a ese cliente. Así que lo vendiste por $ 300 pero lo compraste por $ 100. Puede esperar que su cliente le pague $ 200 para liquidar el saldo. ¿Y qué pasa si usted vendió por $ 500 pero el cliente le paga solo $ 250?

Así que tuve un problema muy complejo que resolver, con muchas posibilidades de que un escenario funcionaría perfectamente pero sería incorrecto en otro tipo de combinación de invocie/pago.

Aquí es donde la prueba de unidad vino al rescate.

Comencé a escribir (dentro del código de prueba) un método para crear una lista de facturas, tanto para ventas como para compras. Luego escribí un segundo método para crear el pago real. Normalmente, un usuario ingresaría esa información a través de una interfaz de usuario.

Luego creé el primer TestMethod, probando un pago muy simple de una sola factura sin ningún descuento de pago. Toda la acción en el sistema sucedería cuando un pago bancario se guardaría en la base de datos. Como puede ver, creé una factura, creé un pago (una transacción bancaria) y guardé la transacción en el disco. En mis afirmaciones, coloco lo que deberían ser los números correctos que terminan en la transacción del Banco y en la Factura vinculada. Verifico el número de pagos, los montos de pago, el monto de descuento y el saldo de la factura después de la transacción.

Después de la prueba, iría a la base de datos y verificaría si lo que esperaba estaba allí.

Después de escribí la prueba, comencé a codificar el método de pago (parte de la clase BankHeader). En la codificación solo me molesté con el código para hacer la primera prueba. Todavía no pensé en los otros escenarios más complejos.

Corrí la primera prueba, arreglé un pequeño error hasta que mi prueba pasara.

Luego comencé a escribir la segunda prueba, esta vez trabajando con un descuento de pago. Después de que escribí la prueba, modifiqué el método de pago para admitir los descuentos.

Al probar la corrección con un descuento de pago, también probé el pago simple. Ambas pruebas deben pasar por supuesto.

Luego me abrí paso a los escenarios más complejos.

1) Piensa en un nuevo escenario.

2) Escribe una prueba para ese escenario

3) Ejecutar esa única prueba para ver si pasaría

4) Si no fuera así, depuraría y modificaría el código hasta que pasara.

5) Mientras modificaba el código, seguí ejecutando todas las pruebas.

Así es como logré crear mi método de pago muy complejo. Sin pruebas de unidad no sabía cómo empezar a codificar, el problema parecía abrumador. Con las pruebas, podría comenzar con un método simple y extenderlo paso a paso con la seguridad de que los escenarios más simples seguirían funcionando.

Estoy seguro de que el uso de la prueba unitaria me ahorró unos días (o semanas) de codificación y está más o menos garantizando la corrección de mi método.

Si luego pienso en un nuevo escenario, puedo agregarlo a las pruebas para ver si está funcionando o no. De lo contrario, puedo modificar el código, pero todavía estoy seguro de que los otros escenarios aún funcionan correctamente. Esto ahorrará días y días en la fase de mantenimiento y corrección de errores.

Sí, incluso el código probado puede tener errores si un usuario hace cosas que no pensó o le impidió hacer

A continuación se muestran solo algunas de las pruebas que he creado para probar mi método de pago.

public class TestPayments
{
    InvoiceDiaryHeader invoiceHeader = null;
    InvoiceDiaryDetail invoiceDetail = null;
    BankCashDiaryHeader bankHeader = null;
    BankCashDiaryDetail bankDetail = null;



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date)
    {
        ......
        ......
    }

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount)
    {
       ......
       ......
       ......
    }


    [TestMethod]
    public void TestSingleSalesPaymentNoDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 1, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSingleSalesPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 2, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    [ExpectedException(typeof(ApplicationException))]
    public void TestDuplicateInvoiceNumber()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("100", true, 2, "01-09-2008"));
        list.Add(CreateSales("200", true, 2, "01-09-2008"));

        bankHeader = CreateMultiplePayments(list, 3, 300, 0);
        bankHeader.Save();
        Assert.Fail("expected an ApplicationException");
    }

    [TestMethod]
    public void TestMultipleSalesPaymentWithPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 11, "01-09-2008"));
        list.Add(CreateSales("400", true, 12, "02-09-2008"));
        list.Add(CreateSales("600", true, 13, "03-09-2008"));
        list.Add(CreateSales("25,40", true, 14, "04-09-2008"));

        bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount);
        Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount);

        Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount);

        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSettlement()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales
        list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase

        bankHeader = CreateMultiplePayments(list, 22, 200, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
    }
38
eroijen

Si realmente son triviales, entonces no te molestes en probar. Por ejemplo, si se implementan así;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Si, por otro lado, está haciendo algo inteligente (como encriptar y descifrar la contraseña en el getter/setter) entonces haga una prueba.

13
Steve Cooper

La regla es que tienes que probar cada pieza de lógica que escribes. Si implementaste alguna funcionalidad específica en los captadores y configuradores, creo que vale la pena probarlos. Si solo asignan valores a algunos campos privados, no se molesten.

10
Slavo

Esta pregunta parece ser una pregunta de dónde se traza la línea sobre qué métodos se prueban y cuáles no.

Los establecedores y captadores para la asignación de valor se han creado teniendo en cuenta la coherencia y el crecimiento futuro, y previendo que en algún momento, el establecedor/captador puede evolucionar hacia operaciones más complejas. Tendría sentido poner a prueba las pruebas unitarias de esos métodos, también en aras de la coherencia y el crecimiento futuro.

La confiabilidad del código, especialmente mientras se realiza un cambio para agregar funcionalidad adicional, es el objetivo principal. No estoy al tanto de que alguien haya sido despedido por incluir setters/getters en la metodología de prueba, pero estoy seguro de que existen personas que desearon haber probado métodos que no sabían o que eran fáciles de recordar eran simples "set/get wrappers" pero no fue así. más largo es el caso.

Tal vez otro miembro del equipo expandió los métodos de establecer/obtener para incluir la lógica que ahora necesita ser probada pero que luego no creó las pruebas. Pero ahora su código está llamando a estos métodos y no está al tanto de que cambiaron y necesitan pruebas en profundidad, y las pruebas que realiza en desarrollo y control de calidad no activan el defecto, pero sí lo hacen los datos comerciales reales el primer día del lanzamiento. dispararlo.

Los dos compañeros de equipo ahora debatirán sobre quién dejó caer el balón y no pudo realizar las pruebas unitarias cuando el conjunto/se transforme para incluir una lógica que puede fallar pero que no está cubierta por una prueba unitaria. Al compañero de equipo que originalmente escribió el set/gets le resultará más fácil salir de este limpio si las pruebas se implementaron desde el primer día en el set/gets simple.

Mi opinión es que unos minutos de tiempo "perdido" que cubren TODOS los métodos con pruebas unitarias, incluso triviales, pueden ahorrarle días de dolor de cabeza y pérdida de dinero/reputación del negocio y pérdida del trabajo de alguien.

Y el hecho de que usted envolvió los métodos triviales con las pruebas unitarias podría ser visto por ese compañero de equipo junior cuando cambian los métodos triviales por otros no triviales y los alienta a actualizar la prueba, y ahora nadie está en problemas porque el defecto estaba contenido De alcanzar la producción.

La forma en que codificamos y la disciplina que se puede ver en nuestro código puede ayudar a otros.

5
Thomas Carlisle

Otra respuesta canónica. Esto, creo, de Ron Jeffries:

Solo prueba el código que quieras trabajar.

4
user9397

El código realmente trivial, como los captadores y los definidores, que no tienen un comportamiento adicional al establecer un campo privado, es una prueba excesiva. En 3.0 C # incluso tiene algo de azúcar sintáctica donde el compilador se ocupa del campo privado para que no tenga que programar eso.

Normalmente escribo muchas pruebas muy simples que verifican el comportamiento que espero de mis clases. Incluso si es algo simple como sumar dos números. Cambio mucho entre escribir una prueba simple y escribir algunas líneas de código. La razón de esto es que luego puedo cambiar el código sin tener miedo de romper cosas en las que no había pensado.

3
Mendelt

Deberías probar todo. En este momento usted tiene captadores y establecedores, pero un día podría cambiarlos un poco, tal vez para hacer la validación o algo más. Las pruebas que escriba hoy se utilizarán mañana para asegurarse de que todo siga funcionando como siempre. Cuando escribes una prueba, debes olvidar consideraciones como "ahora es trivial". En un contexto ágil o basado en pruebas, debe realizar una prueba asumiendo una refactorización futura. Además, ¿intentaste poner valores realmente extraños como cadenas extremadamente largas u otro contenido "malo"? Bueno, deberías ... nunca asumir qué tan mal puede ser abusado tu código en el futuro.

En general, me parece que escribir extensas pruebas de usuario es de un lado, agotador. Por otro lado, aunque siempre le proporciona información valiosa sobre cómo debería funcionar su aplicación y lo ayuda a deshacerse de suposiciones fáciles (y falsas) (como: el nombre de usuario siempre tendrá menos de 1000 caracteres de longitud).

3
Sklivvz

Para los módulos simples que pueden terminar en un kit de herramientas, o en un tipo de proyecto de código abierto, debe probar tanto como sea posible, incluidos los captadores y definidores triviales. Lo que debe tener en cuenta es que generar una prueba de unidad al escribir un módulo en particular es bastante simple y directo. Agregar agregadores y definidores es un código mínimo y se puede manejar sin pensarlo mucho. Sin embargo, una vez que su código se coloca en un sistema más grande, este esfuerzo adicional puede protegerlo contra cambios en el sistema subyacente, como cambios de tipo en una clase base. Probar todo es la mejor manera de tener una regresión completa.

3
Dirigible

Probar el código repetitivo es una pérdida de tiempo, pero como dice Slavo, si agrega un efecto secundario a sus captadores/definidores, debe escribir una prueba para acompañar esa funcionalidad.

Si está realizando un desarrollo guiado por pruebas, primero debe escribir el contrato (por ejemplo, la interfaz) y luego la (s) prueba (s) para ejercer esa interfaz que documente los resultados/comportamiento esperados. Luego escriba sus propios métodos, sin tocar el código en sus pruebas de unidad. Finalmente, tome una herramienta de cobertura de código y asegúrese de que sus pruebas realicen todas las rutas lógicas en su código.

3
warren_s

en general, cuando un método solo se define para ciertos valores, pruebe los valores en y más el borde de lo que es aceptable. En otras palabras, asegúrese de que su método haga lo que se supone que debe hacer, pero nada más. Esto es importante, porque cuando vas a fallar, quieres fallar temprano.

En las jerarquías de herencia, asegúrese de probar LSP compliance.

Para mí, probar los métodos de obtención y configuración predeterminados no me parece muy útil, a menos que esté planeando hacer una validación más adelante.

2
Rik

No hace daño escribir pruebas unitarias para sus captadores y configuradores. En este momento, es posible que solo estén haciendo/obteniendo campos bajo el capó, pero en el futuro puede tener lógica de validación, o dependencias entre propiedades que deben ser probadas. Es más fácil escribirlo ahora mientras lo piensas, y luego recuerda volver a instalarlo si llega el momento.

2
Bob King

Idealmente, habrías hecho tus pruebas de unidad mientras escribías la clase. Esta es la forma en que se supone que debe hacerlo al usar el desarrollo dirigido por pruebas. Agregue las pruebas a medida que implementa cada punto de función, asegurándose de cubrir los casos Edge con la prueba también.

Escribir las pruebas después es mucho más doloroso, pero factible.

Esto es lo que haría en tu posición:

  1. Escribe un conjunto básico de pruebas que prueben la función central.
  2. Obtén NCover y ejecútalo en tus pruebas. Su cobertura de prueba probablemente será de alrededor del 50% en este momento.
  3. Siga agregando pruebas que cubran sus casos Edge hasta que obtenga una cobertura de alrededor del 80% -90%

Esto debería proporcionarle un conjunto de pruebas de unidad de Niza que funcionará como un buen amortiguador contra las regresiones.

El único problema con este enfoque es que el código debe ser diseñado para poder probarse de esta manera. Si cometió algún error de acoplamiento desde el principio, no podrá obtener una alta cobertura con mucha facilidad.

Es por esto que es realmente importante escribir las pruebas antes de escribir el código. Te obliga a escribir código que está ligeramente acoplado.

1
Simon Johnson

Hace que nuestro código sea mejor ... punto!

Una cosa que nosotros los desarrolladores de software olvidamos cuando hacemos un desarrollo basado en pruebas es el propósito detrás de nuestras acciones. Si una prueba de unidad se escribe después de que el código de producción ya está en su lugar, el valor de la prueba disminuye (pero no se pierde por completo).

Con el verdadero espíritu de las pruebas unitarias, estas pruebas son no principalmente para "probar" más de nuestro código; o para obtener un 90% -100% mejor cobertura de código. Estos son todos beneficios adicionales de escribir las pruebas primero. La gran recompensa es que nuestros códigos de producción se escriban mucho mejor debido al proceso natural de TDD.

Para ayudar a comunicar mejor esta idea, lo siguiente puede ser útil en la lectura:

La teoría defectuosa de las pruebas unitarias
Desarrollo de software específico

Si sentimos que el acto de escribir más pruebas unitarias es lo que nos ayuda a obtener un producto de mayor calidad, entonces podemos estar sufriendo de un Cargo Cult de Test Driven Development.

1
Scott Saad

No pruebes el código obviamente activo (repetitivo). Por lo tanto, si sus configuradores y captadores son simplemente "propertyvalue = value" y "return propertyvalue" no tiene sentido probarlo.

1
erlando

Incluso get/set puede tener extrañas consecuencias, dependiendo de cómo se hayan implementado, por lo que deben tratarse como métodos.

Cada prueba de estos tendrá que especificar conjuntos de parámetros para las propiedades, definiendo tanto las propiedades aceptables como las inaceptables para garantizar que las llamadas regresen/fallen de la manera esperada.

También debe tener en cuenta los errores de seguridad, como un ejemplo de inyección de SQL, y probarlos.

Así que sí, debes preocuparte por probar las propiedades.

1
CestLaGalere

Creo que es una tontería poner a prueba a los captadores y definidores cuando solo realizan una operación simple. Personalmente no escribo pruebas unitarias complejas para cubrir cualquier patrón de uso. Intento escribir suficientes pruebas para asegurarme de que he manejado el comportamiento de ejecución normal y la cantidad de casos de error que puedo imaginar. Escribiré más pruebas unitarias como respuesta a los informes de errores. Utilizo la prueba unitaria para garantizar que el código cumpla con los requisitos y para facilitar futuras modificaciones. Me siento mucho más dispuesto a cambiar el código cuando sé que si rompo algo, una prueba fallará.

1
Andrei Savu

bueno, si crees que se puede romper, escribe una prueba para ello. Por lo general, no pruebo el setter/getter, pero te dice que haces uno para User.Name, que concatena el nombre y apellido, escribiría una prueba por lo que si alguien cambia el orden de apellido y nombre, al menos él sabría Él cambió algo que fue probado.

1
pmlarocque

La respuesta canónica es "probar cualquier cosa que pueda romperse". Si está seguro de que las propiedades no se romperán, no las pruebe.

Y una vez que se descubre que algo está roto (encuentras un error), obviamente significa que necesitas probarlo. Escriba una prueba para reproducir el error, vea cómo falla, corríjala y luego pase la prueba.

1
Eric Normand

Si bien es posible adivinar correctamente dónde necesita pruebas su código, generalmente creo que necesita métricas para respaldar esta suposición. Las pruebas unitarias en mi opinión van de la mano con las métricas de cobertura de código.

Código con muchas pruebas pero una pequeña cobertura no ha sido bien probada. Dicho esto, el código con una cobertura del 100% pero sin probar el límite y los casos de error tampoco es excelente.

Desea un equilibrio entre alta cobertura (90% mínimo) y datos de entrada variables.

Recuerde probar para "basura en"!

Además, una prueba de unidad no es una prueba de unidad a menos que compruebe si hay una falla. Las pruebas unitarias que no tienen afirmaciones o están marcadas con excepciones conocidas simplemente probarán que el código no muere cuando se ejecuta.

¡Debe diseñar sus pruebas para que siempre informen fallas o datos inesperados/no deseados!

1
Ray Hayes

Escribiría una prueba para cualquier cosa para la que esté escribiendo código, que se pueda probar fuera de la interfaz GUI.

Por lo general, cualquier lógica que escribo que tenga cualquier lógica empresarial la coloco dentro de otro nivel o capa lógica empresarial.

Luego, escribir pruebas para cualquier cosa que haga algo es fácil de hacer.

Primero pase, escriba una prueba de unidad para cada método público en su "Capa de lógica de negocios".

Si tuviera una clase como esta:

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

Lo primero que haría antes de escribir cualquier código sabiendo que tenía que realizar estas acciones sería comenzar a escribir pruebas unitarias.

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

Escribe tus pruebas para validar el código que has escrito para hacer algo. Si recorres una colección de cosas y cambias algo sobre cada una de ellas, escribe una prueba que haga lo mismo y Afirma que realmente sucedió.

Hay muchos otros enfoques que puede tomar, a saber, Behavoir Driven Development (BDD), que son más complejos y no son un buen lugar para comenzar con sus habilidades de prueba de unidad.

Entonces, la moraleja de la historia es, haga una prueba de cualquier cosa que haga algo por lo que pueda estar preocupado, mantenga las pruebas unitarias probando cosas específicas que son pequeñas en tamaño, muchas pruebas son buenas.

Mantenga la lógica de su negocio fuera de la capa de Interfaz de usuario para que pueda escribir pruebas fácilmente para ellos, y estará bien.

Recomiendo TestDriven.Net o ReSharper ya que ambos se integran fácilmente en Visual Studio.

1
Dean Poulin

Como entiendo las pruebas unitarias en el contexto del desarrollo ágil, Mike, sí, necesitas probar a los captadores y definidores (asumiendo que son visibles públicamente). El concepto completo de prueba de unidad es probar la unidad de software, que es una clase en este caso, como cuadro negro . Dado que los captadores y definidores son visibles externamente, debe probarlos junto con Autenticar y Guardar.

1
Onorio Catenacci

Si los métodos de Autenticación y Guardar usan las propiedades, entonces sus pruebas tocarán las propiedades indirectamente. Siempre y cuando las propiedades solo brinden acceso a los datos, entonces las pruebas explícitas no deberían ser necesarias (a menos que vaya al 100% de cobertura).

1
Tom Walker

Yo probaría a tus captadores y setters. Dependiendo de quién esté escribiendo el código, algunas personas cambian el significado de los métodos de obtención/establecimiento. He visto la inicialización de variables y otras validaciones como parte de los métodos de obtención. Para probar este tipo de cosas, querría que las pruebas de unidad cubran ese código explícitamente.

1
Peter Bernier

Personalmente, me gustaría "probar cualquier cosa que pueda romperse" y el getter simple (o incluso las mejores propiedades automáticas) no se romperá. Nunca me ha fallado una simple declaración de devolución y, por lo tanto, nunca se han realizado pruebas para ellos. Si los captadores tienen cálculos dentro de ellos o alguna otra forma de declaración, sin duda agregaría pruebas para ellos.

Personalmente uso Moq como un marco de objeto simulado y luego verifico que mi objeto llama a los objetos circundantes como debería.

1
tronda

Debe cubrir la ejecución de cada método de la clase con UT y verificar el valor de retorno del método. Esto incluye captadores y definidores, especialmente en el caso de que los miembros (propiedades) sean clases complejas, lo que requiere una gran asignación de memoria durante su inicialización. Llame al colocador con alguna cadena muy grande, por ejemplo (o algo con símbolos griegos) y verifique que el resultado sea correcto (no truncado, la codificación es buena e.t.c.)

En el caso de los enteros simples que también se aplican, ¿qué sucede si se pasa largo en lugar de un entero? Esa es la razón por la que escribes UT para :)

1
m_pGladiator

La prueba de una clase debe verificar que:

  1. los métodos y propiedades devuelven los valores esperados.
  2. Se emiten excepciones apropiadas cuando se proporciona un argumento no válido
  3. Las interacciones entre la clase y otros objetos ocurren como se espera cuando se llama a un método dado

Por supuesto, si los captadores y los definidores no tienen una lógica especial, las pruebas de los métodos Autenticar y Guardar deben cubrirlos, pero de lo contrario se debe escribir una prueba explícita

1
Crippledsmurf

Recomendaría escribir varias pruebas para sus métodos de Autenticación y Guardar. Además del caso de éxito (donde se proporcionan todos los parámetros, todo está escrito correctamente, etc.), es bueno tener pruebas para varios casos de error (parámetros incorrectos o faltantes, conexiones de base de datos no disponibles, si corresponde, etc.). Recomiendo Pruebas de unidades pragmáticas en C # con NUnit como referencia.

Como han dicho otros, las pruebas unitarias para captadores y definidores son excesivas, a menos que haya lógica condicional en sus captadores y definidores.

1
Scott Lawrence

Yo no probaría la configuración real de las propiedades. Me preocuparía más la forma en que esas propiedades son pobladas por el consumidor y con qué las llenan. Con cualquier prueba, debe sopesar los riesgos con el tiempo/costo de la prueba.

1
Bloodhound

Debe probar "todo bloque de código no trivial" utilizando pruebas unitarias en la medida de lo posible.

Si sus propiedades son triviales y es poco probable que alguien introduzca un error, entonces debería ser seguro no probarlas por unidad.

Sus métodos Authenticate () y Save () parecen buenos candidatos para las pruebas.

1
user7015

Escribir código que no tenga valor es siempre una mala idea. Dado que la prueba propuesta no agrega valor a su proyecto (o muy cerca de él). Entonces estás perdiendo un tiempo valioso en el que podrías pasar escribiendo código que realmente aporta valor.

0
pjesi

Apruebo prueba cualquier cosa que pueda romper y no escribo pruebas tontas . Pero el principio más importante es probar que todo lo que encuentre está roto : si algún método se comporta de manera extraña, escriba una prueba para delinear el conjunto de datos que lo hace fallar, luego corrija el error y observe cómo la barra se pone verde. También pruebe los valores de datos "límite" (nulo, 0, MAX_INT, listas vacías, lo que sea).

0
Manrico Corazzi

Al escribir pruebas unitarias, o realmente cualquier prueba, usted determina qué probar examinando las condiciones de contorno de lo que está probando. Por ejemplo, tienes una función llamada is_prime. Afortunadamente, hace lo que su nombre implica y le dice si el objeto entero es primo o no. Para esto supongo que estás usando objetos. Ahora, tendríamos que verificar que se obtuvieron resultados válidos para un rango conocido de objetos primos y no primos. Ese es tu punto de partida.

Básicamente, mire lo que debería suceder con una función, método, programa o script, y luego lo que definitivamente debería no suceder con el mismo código. Esa es la base para su prueba. Solo prepárese para modificar sus pruebas a medida que adquiera más conocimientos sobre lo que debería estar sucediendo con su código.

0
Dan

La mejor regla de oro que he visto es probar que todo lo que no se puede ver de un vistazo, por cierto, funcionará correctamente. Algo más y terminas probando el idioma/entorno.

0
user74754