Ejercicio: Revisión y prueba de una aplicación de consola de C# con datos de ejemplo

Completado

En este ejercicio, revisará y probará el código del proyecto Starter, aislará y corregirá un problema de lógica y, después, comprobará que la aplicación actualizada funciona según lo previsto.

Durante este ejercicio realizará las siguientes tareas:

  1. Revisión del código: revise el contenido del archivo Program.cs.

    El archivo Program.cs incluye las siguientes secciones de código:

    • Instrucciones de nivel superior: las instrucciones de nivel superior simulan una serie de transacciones con una matriz de testData o un número mayor de transacciones generadas aleatoriamente.
    • LoadTillEachMorning: el método LoadTillEachMorning se utiliza para configurar la caja registradora con un número predefinido de billetes de cada valor.
    • MakeChange: el método MakeChange se usa para administrar la caja registradora durante las transacciones de compra.
    • LogTillStatus: el método LogTillStatus se utiliza para mostrar el número de billetes de cada valor que hay actualmente en la caja registradora.
    • TillAmountSummary: el método TillAmountSummary se usa para mostrar un mensaje que indica la cantidad de efectivo que hay en la caja.
  2. Pruebas iniciales: compruebe que MakeChange cuadra correctamente la caja registradora cuando se usa la matriz testData para simular transacciones.

  3. Depuración del código: aísle y corrija un problema de lógica que se expone al usar los datos generados aleatoriamente.

  4. Prueba de comprobación: realice una prueba de comprobación en el código que desarrolla en este ejercicio.

Revisión del contenido del archivo Program.cs

En esta tarea, hace un recorrido por el código del proyecto Starter. El archivo Program.cs contiene una aplicación que simula las condiciones de las transacciones diarias. La aplicación llama al método MakeChange para administrar la caja registradora durante cada transacción. Se usan otros métodos para inicializar la caja y generar mensajes informativos.

  1. Asegúrese de que la carpeta ChallengeProject está abierta en Visual Studio Code.

  2. En la vista EXPLORADOR, expanda las carpetas ChallengeProject y Starter.

    La carpeta Starter contiene la aplicación de ejemplo para este módulo de proyecto guiado.

  3. Abra el archivo Program.cs en el editor de Visual Studio Code.

  4. En el menú Vista, seleccione Paleta de comandos.

  5. En el símbolo del sistema, escriba .net: g y, después, presione .NET: Generar recursos para compilar y depurar.

  6. En el mensaje Seleccione el proyecto que desea iniciar, elija el proyecto Starter.

    El archivo launch.json que se crea incluirá la configuración para el proyecto Starter.

  7. Dedique unos minutos a revisar las instrucciones de nivel superior de esta aplicación:

    /*
    This application manages transactions at a store check-out line. The
    check-out line has a cash register, and the register has a cash till
    that is prepared with a number of bills each morning. The till includes
    bills of four denominations: $1, $5, $10, and $20. The till is used
    to provide the customer with change during the transaction. The item 
    cost is a randomly generated number between 2 and 49. The customer 
    offers payment based on an algorithm that determines a number of bills
    in each denomination. 
    
    Each day, the cash till is loaded at the start of the day. As transactions
    occur, the cash till is managed in a method named MakeChange (customer 
    payments go in and the change returned to the customer comes out). A 
    separate "safety check" calculation that's used to verify the amount of
    money in the till is performed in the "main program". This safety check
    is used to ensure that logic in the MakeChange method is working as 
    expected.
    */
    
    string? readResult = null;
    bool useTestData = true;
    
    Console.Clear();
    
    int[] cashTill = new int[] { 0, 0, 0, 0 };
    int registerCheckTillTotal = 0;
    
    // registerDailyStartingCash: $1 x 50, $5 x 20, $10 x 10, $20 x 5 => ($350 total)
    int[,] registerDailyStartingCash = new int[,] { { 1, 50 }, { 5, 20 }, { 10, 10 }, { 20, 5 } };
    
    int[] testData = new int[] { 6, 10, 17, 20, 31, 36, 40, 41 };
    int testCounter = 0;
    
    LoadTillEachMorning(registerDailyStartingCash, cashTill);
    
    registerCheckTillTotal = registerDailyStartingCash[0, 0] * registerDailyStartingCash[0, 1] + registerDailyStartingCash[1, 0] * registerDailyStartingCash[1, 1] + registerDailyStartingCash[2, 0] * registerDailyStartingCash[2, 1] + registerDailyStartingCash[3, 0] * registerDailyStartingCash[3, 1];
    
    // display the number of bills of each denomination currently in the till
    LogTillStatus(cashTill);
    
    // display a message showing the amount of cash in the till
    Console.WriteLine(TillAmountSummary(cashTill));
    
    // display the expected registerDailyStartingCash total
    Console.WriteLine($"Expected till value: {registerCheckTillTotal}\n\r");
    
    var valueGenerator = new Random((int)DateTime.Now.Ticks);
    
    int transactions = 10;
    
    if (useTestData)
    {
        transactions = testData.Length;
    }
    
    while (transactions > 0)
    {
        transactions -= 1;
        int itemCost = valueGenerator.Next(2, 20);
    
        if (useTestData)
        {
            itemCost = testData[testCounter];
            testCounter += 1;
        }
    
        int paymentOnes = itemCost % 2;                 // value is 1 when itemCost is odd, value is 0 when itemCost is even
        int paymentFives = (itemCost % 10 > 7) ? 1 : 0; // value is 1 when itemCost ends with 8 or 9, otherwise value is 0
        int paymentTens = (itemCost % 20 > 13) ? 1 : 0; // value is 1 when 13 < itemCost < 20 OR 33 < itemCost < 40, otherwise value is 0
        int paymentTwenties = (itemCost < 20) ? 1 : 2;  // value is 1 when itemCost < 20, otherwise value is 2
    
        // display messages describing the current transaction
        Console.WriteLine($"Customer is making a ${itemCost} purchase");
        Console.WriteLine($"\t Using {paymentTwenties} twenty dollar bills");
        Console.WriteLine($"\t Using {paymentTens} ten dollar bills");
        Console.WriteLine($"\t Using {paymentFives} five dollar bills");
        Console.WriteLine($"\t Using {paymentOnes} one dollar bills");
    
        // MakeChange manages the transaction and updates the till 
        string transactionMessage = MakeChange(itemCost, cashTill, paymentTwenties, paymentTens, paymentFives, paymentOnes);
    
        // Backup Calculation - each transaction adds current "itemCost" to the till
        if (transactionMessage == "transaction succeeded")
        {
            Console.WriteLine($"Transaction successfully completed.");
            registerCheckTillTotal += itemCost;
        }
        else
        {
            Console.WriteLine($"Transaction unsuccessful: {transactionMessage}");
        }
    
        Console.WriteLine(TillAmountSummary(cashTill));
        Console.WriteLine($"Expected till value: {registerCheckTillTotal}\n\r");
        Console.WriteLine();
    }
    
    Console.WriteLine("Press the Enter key to exit");
    do
    {
        readResult = Console.ReadLine();
    
    } while (readResult == null);
    

    El código de las instrucciones de nivel superior lleva a cabo las siguientes tareas:

    • Configura los datos de la aplicación y las variables de entorno que se usan para probar el método MakeChange.
    • Llama a los métodos LoadTillEachMorning(), LogTillStatus() y TillAmountSummary() para preparar la caja registradora e imprime los mensajes de estado en la consola.
    • Usa un bucle while para simular una serie de transacciones.
    • Llama al método MakeChange desde el bloque de código del bucle while.
    • Informa sobre del estado de la caja registradora después de cada transacción.

    Nota

    Las instrucciones de nivel superior incluyen una instrucción Console.ReadLine(). Será necesario actualizar el archivo launch.json antes de la depuración.

  8. Dedique un momento a revisar el método LoadTillEachMorning().

    static void LoadTillEachMorning(int[,] registerDailyStartingCash, int[] cashTill)
    {
        cashTill[0] = registerDailyStartingCash[0, 1];
        cashTill[1] = registerDailyStartingCash[1, 1];
        cashTill[2] = registerDailyStartingCash[2, 1];
        cashTill[3] = registerDailyStartingCash[3, 1];
    }
    
  9. Dedique un par de minutos a revisar el método MakeChange().

    static string MakeChange(int cost, int[] cashTill, int twenties, int tens = 0, int fives = 0, int ones = 0)
    {
        string transactionMessage = "";
    
        cashTill[3] += twenties;
        cashTill[2] += tens;
        cashTill[1] += fives;
        cashTill[0] += ones;
    
        int amountPaid = twenties * 20 + tens * 10 + fives * 5 + ones;
        int changeNeeded = amountPaid - cost;
    
        if (changeNeeded < 0)
            transactionMessage = "Not enough money provided.";
    
        Console.WriteLine("Cashier Returns:");
    
        while ((changeNeeded > 19) && (cashTill[3] > 0))
        {
            cashTill[3]--;
            changeNeeded -= 20;
            Console.WriteLine("\t A twenty");
        }
    
        while ((changeNeeded > 9) && (cashTill[2] > 0))
        {
            cashTill[2]--;
            changeNeeded -= 10;
            Console.WriteLine("\t A ten");
        }
    
        while ((changeNeeded > 4) && (cashTill[1] > 0))
        {
            cashTill[2]--;
            changeNeeded -= 5;
            Console.WriteLine("\t A five");
        }
    
        while ((changeNeeded > 0) && (cashTill[0] > 0))
        {
            cashTill[0]--;
            changeNeeded--;
            Console.WriteLine("\t A one");
        }
    
        if (changeNeeded > 0)
            transactionMessage = "Can't make change. Do you have anything smaller?";
    
        if (transactionMessage == "")
            transactionMessage = "transaction succeeded";
    
        return transactionMessage;
    }
    

    El método MakeChange administra la caja registradora durante cada transacción de compra. El proceso de transacción se basa en los siguientes recursos y condiciones:

    • Transacción en efectivo: el método MakeChange acepta un pago en efectivo del cliente y, después, determina cuántos billetes de cada valor deben devolverse al cliente como cambio. MakeChange debe asegurarse primero de que el cliente ha proporcionado suficiente dinero para cubrir la transacción. Si el pago es suficiente, el proceso de "devolver el cambio" comienza con el billete de mayor valor y continúa hasta el billete de menor valor. En cada etapa, MakeChange se asegura de que el valor actual es menor que el cambio debido. MakeChange también se asegura de que haya un billete del valor necesario en la caja antes de agregarlo al cambio devuelto al cliente.

    • Parámetros de entrada: el método MakeChange utiliza los siguientes parámetros de entrada:

      • Entero que representa el costo del artículo que se compra: itemCost.
      • Matriz de enteros que contiene el número de billetes de cada valor que hay en la caja: cashTill.
      • Pago que ofrece el cliente. El número de billetes de cada valor se especifica por separado: paymentTwenties, paymentTens, paymentFives, paymentOnes.
    • Efectivo disponible en la caja: los billetes que el cliente ofrece como pago deben incluirse en los billetes de cada valor que hay disponibles para dar el cambio.

    • Cambio debido al cliente: el cambio que se le debe al cliente se calcula con el importe que paga el cliente menos el costo del artículo.

    • Pago insuficiente: si el cliente no proporciona un pago suficiente, MakeChange devuelve un mensaje descriptivo y se cancela la transacción.

    • Caja insuficiente: si la caja registradora no puede proporcionar el cambio exacto, MakeChange devuelve un mensaje descriptivo y se cancela la transacción.

  10. Dedique un momento a revisar el método LogTillStatus().

    static void LogTillStatus(int[] cashTill)
    {
        Console.WriteLine("The till currently has:");
        Console.WriteLine($"{cashTill[3] * 20} in twenties");
        Console.WriteLine($"{cashTill[2] * 10} in tens");
        Console.WriteLine($"{cashTill[1] * 5} in fives");
        Console.WriteLine($"{cashTill[0]} in ones");
        Console.WriteLine();
    }
    

    El método LogTillStatus usa la matriz cashTill para informar del contenido actual de la caja.

  11. Dedique un momento a revisar el método TillAmountSummary().

    static string TillAmountSummary(int[] cashTill)
    {
        return $"The till has {cashTill[3] * 20 + cashTill[2] * 10 + cashTill[1] * 5 + cashTill[0]} dollars";
    
    }
    

    El método TillAmountSummary usa la matriz cashTill para calcular el saldo en efectivo actual que hay disponible en la caja registradora.

Esto completa la revisión del proyecto de código.

Compruebe que MakeChange administra correctamente el dinero cuando se usa la matriz testData.

En esta tarea, simula transacciones con la matriz testData y comprueba que MakeChange cuadra correctamente la caja registradora.

  1. En el menú Ejecutar de Visual Studio Code, seleccione Iniciar depuración.

  2. Observe que se produce un error IOException.

    La CONSOLA DE DEPURACIÓN no admite los métodos Console.Clear() y Console.ReadLine(). Debe actualizar el archivo launch.json antes de la depuración.

  3. En la barra de herramientas Depurar, seleccione Detener.

  4. Use la vista EXPLORADOR para abrir el archivo launch.json.

  5. En el archivo launch.json, actualice el atributo de la console siguiente manera:

    // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
    "console":"integratedTerminal",
    

    El valor predeterminado del atributo console es internalConsole, que concuerda con el panel CONSOLA DE DEPURACIÓN. Lamentablemente, el panel CONSOLA DE DEPURACIÓN no admite algunos métodos de consola. El valor integratedTerminal concuerda con el panel TERMINAL, que admite entradas y salidas de la consola.

  6. Guarde los cambios en el archivo launch.json.

  7. En el menú Ejecutar de Visual Studio Code, seleccione Iniciar depuración.

  8. Revise la salida generada por la aplicación en el panel TERMINAL.

    Cambie del panel CONSOLA DE DEPURACIÓN al panel TERMINAL.

  9. Observe que MakeChange cuadra correctamente la caja cuando se usa la matriz testData para simular transacciones.

    Debería ver las siguientes líneas al final de la salida:

    The till has 551 dollars
    Expected till value: 551
    
    
    Press the Enter key to exit
    

    Observe que el valor notificado y el valor esperado de la caja son 551.

  10. Presione Entrar para salir de la aplicación.

Identificación y corrección de problemas de lógica

En esta tarea, utiliza transacciones simuladas para exponer un problema de lógica del código y, después, usa las herramientas del depurador de Visual Studio Code para aislar y corregir el problema.

  1. Para ejecutar el código usando transacciones generadas aleatoriamente, cambie el valor de useTestData a false.

    La variable useTestData se encuentra cerca del principio de las instrucciones de nivel superior.

  2. Guarde el archivo Program.cs y ejecute la aplicación en el depurador.

  3. Revise la salida en el panel TERMINAL.

  4. Observe la discrepancia en el saldo de la caja.

    Al final de la salida, se notifican el saldo final de la caja calculado por MakeChange y el saldo mantenido en las instrucciones de nivel superior. Por ejemplo:

    Transaction successfully completed.
    The till has 379 dollars
    Expected till value: 434
    
    
    Press the Enter key to exit
    

    Nota

    La aplicación genera aleatoriamente el costo de los artículos de compra. Por tanto, los valores de la caja notificados en la salida son diferentes.

  5. Presione Entrar para salir de la aplicación.

  6. Cierre el panel TERMINAL.

Depurar el código

En esta tarea, usa las herramientas del depurador de Visual Studio Code para aislar y corregir el problema de lógica.

  1. Cerca del final de las instrucciones de nivel superior, busque la siguiente línea de código:

    Console.WriteLine();
    
  2. Establezca un punto de interrupción en la línea de código seleccionada.

  3. En el menú Ejecutar de Visual Studio Code, seleccione Iniciar depuración.

  4. Observe que la ejecución del código se detiene en el punto de interrupción.

  5. En la barra de herramientas Controles de depuración, seleccione Depurar paso a paso por instrucciones.

  6. Revise la salida en el panel TERMINAL.

  7. Si el valor notificado y el valor esperado de la caja son iguales, seleccione Continuar en la barra de herramientas Controles de depuración.

  8. Repita el paso anterior hasta que vea una discrepancia entre el valor notificado y el valor esperado de la caja.

  9. Cuando vea una discrepancia, dedique un minuto a examinar los detalles de la transacción.

  10. Observe que el efectivo recibido y el cambio devuelto notificados son correctos, pero el valor de la caja es cinco dólares menor.

    Esta diferencia sugiere que la matriz cashTill se está actualizando incorrectamente, aunque las notificaciones sean correctas.

  11. Detenga la sesión de depuración y cierre el panel TERMINAL.

  12. Desplácese hasta el final del método MakeChange.

    Las instrucciones while que se usan para "devolver el cambio" están al final del método MakeChange.

  13. Revise los bloques de código de la instrucción while que se usan para devolver el cambio.

    Dado que la caja tiene un desfase de cinco dólares, es probable que el problema esté en el bloque de código while que se usa para devolver billetes de cinco dólares.

  14. Observe el siguiente código:

    while ((changeNeeded > 4) && (cashTill[1] > 0))
    {
        cashTill[2]--;
        changeNeeded -= 5;
        Console.WriteLine("\t A five");
    }    
    

    La matriz cashTill[] se utiliza para almacenar el número de billetes de cada valor que hay disponibles actualmente. El elemento 1 de la matriz se usa para administrar los billetes de cinco dólares que hay en la caja. La expresión de la instrucción while hace referencia a cashTill[1] correctamente. Sin embargo, la instrucción que hay dentro del bloque de código disminuye cashTill[2] en lugar de cashTill[1]. Especificar un valor de índice de 2 significa que se quita un billete de diez dólares de la caja en lugar de un billete de cinco dólares.

  15. Actualice el bloque de código while de la siguiente manera:

    while ((changeNeeded > 4) && (cashTill[1] > 0))
    {
        cashTill[1]--;
        changeNeeded -= 5;
        Console.WriteLine("\t A five");
    }    
    
  16. Guarde el archivo Program.cs.

Comprobar el trabajo

En esta tarea, ejecuta la aplicación y comprueba que el código actualizado funciona según lo previsto.

  1. En el menú Ejecutar de Visual Studio Code, seleccione Quitar todos los puntos de interrupción.

  2. En el menú Ejecutar, seleccione Iniciar depuración.

  3. Revise la salida en el panel TERMINAL.

  4. Compruebe que el valor notificado de la caja registradora es igual al valor esperado:

    Al final de la salida, se notifican el saldo final de la caja calculado por MakeChange y el saldo mantenido en las instrucciones de nivel superior. Por ejemplo:

    Transaction successfully completed.
    The till has 452 dollars
    Expected till value: 452
    
    
    Press the Enter key to exit
    

    La aplicación genera aleatoriamente el costo de los artículos de compra. Por tanto, los valores de la caja notificados en la salida son diferentes. Si los dos valores son iguales, significa que ha corregido el problema de lógica.