Esercizio - Esaminare e testare un'applicazione console C# usando dati di esempio

Completato

In questo esercizio si esaminerà e testerà il codice nel progetto Starter, si isolerà e risolverà un problema di logica e quindi si verificherà che l'applicazione aggiornata funzioni come previsto.

Durante l'esercizio verranno completate le attività seguenti:

  1. Revisione del codice: esaminare il contenuto del file Program.cs.

    Program.cs include le sezioni di codice seguenti:

    • Istruzioni di primo livello: le istruzioni di primo livello simulano una serie di transazioni usando una matrice di testData o un numero maggiore di transazioni generate in modo casuale.
    • LoadTillEachMorning: il metodo LoadTillEachMorning viene usato per configurare la cassa del registratore di cassa con un numero predefinito di banconote di ogni taglio.
    • MakeChange: il metodo MakeChange viene usato per gestire il denaro in cassa durante le transazioni di acquisto.
    • LogTillStatus: il metodo LogTillStatus viene usato per visualizzare il numero di banconote di ogni taglio attualmente presenti in cassa.
    • TillAmountSummary: il metodo TillAmountSummary viene usato per visualizzare un messaggio che mostra l'importo del contante disponibile in cassa.
  2. Test iniziale: verificare che MakeChange calcoli correttamente il saldo di cassa quando viene usata la matrice testData per simulare le transazioni.

  3. Debug del codice: isolare e correggere un problema di logica esposto quando si usano dati generati in modo casuale.

  4. Test di verifica: eseguire un test di verifica sul codice sviluppato in questo esercizio.

Esaminare il contenuto del file Program.cs

In questa attività si completerà una procedura dettagliata del codice del progetto Starter. Il file Program.cs contiene un'applicazione che simula le condizioni per le transazioni giornaliere. L'applicazione chiama il metodo MakeChange per gestire il denaro in cassa durante ogni transazione. Altri metodi vengono usati per inizializzare la cassa e generare messaggi di segnalazione.

  1. Assicurarsi che la cartella GuidedProject sia aperta in Visual Studio Code.

  2. Nella visualizzazione EXPLORER espandere le cartelle GuidedProject e Starter.

    La cartella Starter contiene l'applicazione di esempio per questo modulo di progetto guidato.

  3. Aprire il file Program.cs nell'editor di Visual Studio Code.

  4. Nel menu Visualizza selezionare Riquadro comandi.

  5. Al prompt dei comandi immettere .net: g e quindi selezionare .NET: Generare asset per la compilazione e il debug.

  6. Al prompt Selezionare il progetto da avviare specificare il progetto Starter.

    Il file launch.json creato includerà una configurazione per il progetto Starter.

  7. Soffermarsi qualche istante a esaminare le istruzioni di primo livello per questa applicazione:

    /*
    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);
    

    Il codice delle istruzioni di primo livello completa le attività seguenti:

    • Configura i dati dell'applicazione e le variabili di ambiente usati per testare il metodo MakeChange.
    • Chiama i metodi LoadTillEachMorning(), LogTillStatus() e TillAmountSummary() per preparare il saldo di cassa e stampare i messaggi di stato sulla console.
    • Usa un ciclo while per simulare una serie di transazioni.
    • Chiama il metodo MakeChange dall'interno del blocco di codice del ciclo while.
    • Segnala lo stato del denaro in cassa dopo ogni transazione.

    Nota

    Le istruzioni di primo livello includono un'istruzione Console.ReadLine(). Il file launch.json deve essere aggiornato prima del debug.

  8. Dedicare qualche minuto all'esame del metodo 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. Dedicare qualche altro istante all'esame del metodo 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;
    }
    

    Il metodo MakeChange gestisce il denaro in cassa durante ogni transazione di acquisto. Il processo di transazione si basa sulle risorse e sulle condizioni seguenti:

    • Transazione in contanti: il metodo MakeChange accetta un pagamento in contanti dal cliente e quindi determina il numero di banconote di ogni taglio da dare di resto al cliente. MakeChange deve prima assicurarsi che il cliente abbia fornito abbastanza denaro per pagare la transazione. Se l'importo è sufficiente, il processo di restituzione del resto inizia con la banconota di taglio più grande fino a quella di taglio più piccolo. In ogni fase, MakeChange verifica che il taglio corrente sia inferiore all'importo del resto dovuto. MakeChange verifica inoltre che in cassa sia disponibile una banconota del taglio richiesto prima di aggiungerla al resto da dare al cliente.

    • Parametri di input: il metodo MakeChange usa i parametri di input seguenti:

      • Un valore integer che rappresenta il costo dell'articolo acquistato: itemCost
      • Una matrice integer che contiene il numero di banconote in cassa per ogni taglio: cashTill
      • Il pagamento effettuato dal cliente, in cui è specificato separatamente il numero di banconote per ogni taglio: paymentTwenties, paymentTens, paymentFives, paymentOnes
    • Contanti disponibili in cassa: le banconote consegnate dal cliente per il pagamento devono essere incluse nelle banconote di ogni taglio disponibili per dare il resto.

    • Resto dovuto al cliente: il resto dovuto al cliente viene calcolato sottraendo il costo dell'articolo all'importo pagato dal cliente.

    • Pagamento insufficiente: se il cliente non ha fornito denaro sufficiente, MakeChange restituisce un messaggio descrittivo e la transazione viene annullata.

    • Cassa insufficiente: se il denaro in cassa non è sufficiente per dare il resto esatto, MakeChange restituisce un messaggio descrittivo e la transazione viene annullata.

  10. Dedicare qualche minuto all'esame del metodo 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();
    }
    

    Il metodo LogTillStatus usa la matrice cashTill per riportare il contenuto corrente della cassa.

  11. Dedicare qualche minuto all'esame del metodo TillAmountSummary().

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

    Il metodo TillAmountSummary usa la matrice cashTill per calcolare il saldo corrente disponibile in cassa.

A questo punto, la revisione del progetto di codice esistente è completata.

Verificare che MakeChange gestisca il denaro correttamente quando si usa la matrice testData

In questa attività si simuleranno le transazioni usando la matrice testData e si verificherà che MakeChange calcoli correttamente il saldo di cassa.

  1. Nel menu Esegui di Visual Studio Code selezionare Avvia debug.

  2. Si noti che viene restituito un errore IOException.

    La CONSOLE DI DEBUG non supporta i metodi Console.Clear() o Console.ReadLine(). È necessario aggiornare il file launch.json prima del debug.

  3. Sulla barra degli strumenti Debug selezionare Arresta.

  4. Usare la visualizzazione EXPLORER per aprire il file launch.json.

  5. Nel file launch.json aggiornare l'attributo console nel modo seguente:

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

    Il valore predefinito per l'attributo console è internalConsole, che è allineato al pannello CONSOLE DI DEBUG. Sfortunatamente, il pannello CONSOLE DI DEBUG non supporta alcuni metodi della console. L'impostazione integratedTerminal è allineata al pannello TERMINALE, che supporta l'input e l'output della console.

  6. Salvare le modifiche apportate al file launch.json.

  7. Nel menu Esegui di Visual Studio Code selezionare Avvia debug.

  8. Esaminare l'output generato dall'applicazione nel pannello TERMINALE.

    Passare dal pannello CONSOLE DI DEBUG al pannello TERMINALE per esaminare l'output.

  9. Si noti che MakeChange calcola correttamente il saldo di cassa quando viene usata la matrice testData per simulare le transazioni.

    Nella parte inferiore dell'output riportato dovrebbero essere elencate le righe seguenti:

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

    Si noti che il valore di cassa riportato e quello previsto sono entrambi 551.

  10. Per uscire dall'applicazione, premere INVIO.

Identificare e risolvere i problemi di logica

In questa attività si useranno le transazioni simulate per esporre un problema di logica del codice e quindi si useranno gli strumenti del debugger di Visual Studio Code per isolare e risolvere il problema.

  1. Per eseguire il codice usando transazioni generate in modo casuale, modificare il valore assegnato a useTestData specificando false.

    È possibile trovare la variabile useTestData nella parte superiore delle istruzioni di primo livello.

  2. Salvare il file Program.cs e quindi eseguire l'applicazione nel debugger.

  3. Esaminare l'output nel pannello TERMINALE.

  4. Si noti la discrepanza nel saldo di cassa.

    Il saldo di cassa finale calcolato da MakeChange e il saldo gestito nelle istruzioni di primo livello sono riportati nella parte inferiore dell'output. Ad esempio:

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

    Nota

    L'applicazione genera in modo casuale il costo degli articoli di acquisto. Pertanto, i valori di cassa riportati nell'output sono diversi.

  5. Per uscire dall'applicazione, premere INVIO.

  6. Chiudere il pannello TERMINALE.

Eseguono il debug del codice

In questa attività si useranno gli strumenti del debugger di Visual Studio Code per isolare e quindi risolvere il problema di logica.

  1. Verso la fine delle istruzioni di primo livello individuare la riga di codice seguente:

    Console.WriteLine();
    
  2. Impostare un punto di interruzione sulla riga di codice selezionata.

  3. Nel menu Esegui di Visual Studio Code selezionare Avvia debug.

  4. Si noti che l'esecuzione del codice viene sospesa in corrispondenza del punto di interruzione.

  5. Sulla barra degli strumenti Controlli di debug selezionare Esegui istruzione.

  6. Esaminare l'output nel pannello TERMINALE.

  7. Se il valore di cassa riportato e quello previsto sono uguali, selezionare Continua sulla barra degli strumenti Controlli di debug.

  8. Ripetere il passaggio precedente finché non viene visualizzata una discrepanza tra il valore di cassa riportato e quello previsto.

  9. Quando viene visualizzata una discrepanza, soffermarsi qualche istante a esaminare i dettagli della transazione.

  10. Si noti che l'importo del denaro ricevuto e quello del resto consegnato sono corretti, ma in cassa mancano cinque dollari.

    Questa carenza suggerisce che la matrice cashTill non viene aggiornata correttamente, anche se sono riportati i dati corretti.

  11. Arrestare la sessione di debug e chiudere il pannello TERMINALE.

  12. Scorrere fino alla fine del metodo MakeChange.

    Le istruzioni while usate per "dare il resto" si trovano alla fine del metodo MakeChange.

  13. Esaminare i blocchi di codice dell'istruzione while usati per dare il resto.

    Dal momento che in cassa mancano cinque dollari, il problema è presumibilmente dovuto al blocco di codice while usato per restituire le banconote da cinque dollari.

  14. Si noti il codice seguente:

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

    La matrice cashTill[] viene usata per archiviare il numero di banconote di ogni taglio attualmente disponibili. L'elemento di matrice 1 viene usato per gestire il numero di banconote da cinque dollari in cassa. L'espressione nell'istruzione while fa riferimento a cashTill[1] in modo corretto. Tuttavia, l'istruzione all'interno del blocco di codice decrementa cashTill[2] anziché cashTill[1]. Se si specifica un valore di indice 2, dalla cassa risulta rimossa una banconota da dieci dollari invece che da cinque.

  15. Aggiornare il blocco di codice while come indicato di seguito:

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

Controlla il tuo lavoro

In questa attività si eseguirà l'applicazione e si verificherà che il codice aggiornato funzioni come previsto.

  1. Nel menu Esegui di Visual Studio Code selezionare Rimuovi tutti i punti di interruzione.

  2. Nel menu Esegui selezionare Avvia debug.

  3. Esaminare l'output nel pannello TERMINALE.

  4. Verificare che il valore di cassa riportato equivalga al valore di cassa previsto:

    Il saldo di cassa finale calcolato da MakeChange e il saldo gestito nelle istruzioni di primo livello sono riportati nella parte inferiore dell'output. Ad esempio:

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

    L'applicazione genera in modo casuale il costo degli articoli di acquisto. Pertanto, i valori di cassa riportati nell'output sono diversi. Se i due valori sono uguali, il problema di logica è stato risolto.