연습 - 샘플 데이터를 사용하여 C# 콘솔 애플리케이션 검토 및 테스트

완료됨

이 연습에서는 Starter 프로젝트에서 코드를 검토 및 테스트하고, 논리 문제를 격리 및 수정한 다음 업데이트된 애플리케이션이 예상대로 작동하는지 확인합니다.

이 연습에서는 다음 작업을 완료합니다.

  1. 코드 검토: Program.cs 파일의 내용을 검토합니다.

    Program.cs에는 다음 코드 섹션이 포함되어 있습니다.

    • 최상위 문: 최상위 문은 testData의 배열 또는 더 많은 수의 임의로 생성된 거래를 사용하여 일련의 거래를 시뮬레이션합니다.
    • LoadTillEachMorning: LoadTillEachMorning 메서드를 사용하여 각 액면 금액에 미리 정의된 수의 지폐를 사용하여 현금출납기를 구성할 수 있습니다.
    • MakeChange: MakeChange 메서드는 구매 거래 동안 현금출납기를 관리하는 데 사용됩니다.
    • LogTillStatus: LogTillStatus 메서드는 현재 현금출납기에 있는 각 액면 금액의 지폐 수를 표시하는 데 사용됩니다.
    • TillAmountSummary: TillAmountSummary 메서드를 사용하면 현금출납기의 현금 금액을 보여 주는 메시지가 표시됩니다.
  2. 초기 테스트: MakeChange 배열을 사용하여 거래를 시뮬레이션할 때 testData가 현금출납기의 잔액을 성공적으로 관리하는지 확인합니다.

  3. 코드 디버깅: 임의로 생성된 데이터를 사용할 때 노출되는 논리 문제를 격리하고 수정합니다.

  4. 확인 테스트: 이 연습에서 개발하는 코드에 대한 확인 테스트를 수행합니다.

Program.cs 파일의 내용 검토

이 작업에서는 Starter 프로젝트 코드 연습을 완료합니다. Program.cs 파일에는 일일 거래의 조건을 시뮬레이션하는 애플리케이션이 포함되어 있습니다. 애플리케이션은 각 거래 중에 현금출납기를 관리하는 MakeChange 메서드를 호출합니다. 다른 메서드는 현금출납기를 초기화하고 보고 메시지를 생성하는 데 사용됩니다.

  1. Visual Studio Code에서 GuidedProject 폴더가 열려 있는지 확인합니다.

  2. EXPLORER 보기에서 GuidedProjectStarter 폴더를 확장합니다.

    Starter 폴더에는 이 Guided 프로젝트 모듈의 애플리케이션 예제가 포함되어 있습니다.

  3. Visual Studio Code 편집기에서 Program.cs 파일을 엽니다.

  4. 보기 메뉴에서 명령 팔레트를 선택합니다.

  5. 명령 프롬프트에 .net: g를 입력한 다음 .NET:을 선택합니다. 빌드 및 디버그를 위한 자산을 생성합니다.

  6. 시작할 프로젝트 선택 프롬프트에서 Starter 프로젝트를 선택합니다.

    생성된 launch.json 파일에는 Starter 프로젝트에 대한 구성이 포함되어 있습니다.

  7. 이 애플리케이션의 최상위 수준의 진술을 검토하는 데 몇 분을 할애하세요.

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

    최상위 문 코드는 다음 작업을 완료합니다.

    • MakeChange 메서드를 테스트하는 데 사용되는 애플리케이션 데이터 및 환경 변수를 구성합니다.
    • LoadTillEachMorning(), LogTillStatus()TillAmountSummary() 메서드를 호출하여 현금출납기를 준비하고 콘솔에 상태 메시지를 출력합니다.
    • while 루프를 사용하여 일련의 거래를 시뮬레이션합니다.
    • MakeChange 루프의 코드 블록 내에서 while 메서드를 호출합니다.
    • 각 거래 후 현금출납기의 상태를 보고합니다.

    참고

    최상위 문에는 Console.ReadLine() 문이 포함됩니다. 디버그하기 전에 launch.json 파일을 업데이트해야 합니다.

  8. 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. 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;
    }
    

    MakeChange 메서드는 각 구매 거래에서 현금출납기를 관리합니다. 거래 프로세스는 다음 리소스 및 조건에 의존합니다.

    • 현금 거래: MakeChange 메서드는 고객으로부터 현금 지불을 수락한 다음 고객에게 거스름돈으로 반환해야 하는 각 액면 금액의 지폐 수를 결정합니다. MakeChange는 먼저 고객이 거래를 충당하기에 충분한 금액을 지불했는지 확인해야 합니다. 지불 금액이 충분하면 "거스름돈 지불" 프로세스는 최고 액면 금액의 지폐로 시작하여 최저 액면 금액으로 내려갑니다. 각 단계에서 MakeChange는 현재 액면 금액이 지불할 거스름돈보다 작은지 확인합니다. 또한 MakeChange는 고객에게 반환된 거스름돈에 추가하기 전에 현금출납기에 필요한 액면 금액의 지폐가 있는지 확인합니다.

    • 입력 매개 변수: MakeChange 메서드는 다음 입력 매개 변수를 사용합니다.

      • 구매 중인 항목의 비용을 나타내는 정수: itemCost
      • 현금출납기에 있는 각 액면 금액의 지폐 수를 포함하는 정수 배열: cashTill
      • 고객이 지불한 금액(각 액면 금액의 지폐 수가 별도로 지정됨): paymentTwenties, paymentTens, paymentFives, paymentOnes
    • 현금출납기의 현금 사용 가능 고객이 결제 수단으로 제시한 지폐는 거스름돈으로 사용할 수 있는 각 종류의 지폐에 포함되어야 합니다.

    • 고객에게 지불할 거스름돈: 고객에게 지불해야 하는 거스름돈은 고객이 지불한 금액에서 항목 비용을 뺀 금액을 사용하여 계산됩니다.

    • 미지급: 고객이 충분한 금액을 지불하지 않은 경우 MakeChange가 설명 메시지를 반환하고 거래가 취소됩니다.

    • 현금출납기 부족: 계산대에서 정확한 변경을 할 수 없는 경우 MakeChange는 설명 메시지를 반환하고 트랜잭션은 취소됩니다.

  10. 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();
    }
    

    LogTillStatus 메서드는 cashTill 배열을 사용하여 현금출납기의 현재 내용을 보고합니다.

  11. TillAmountSummary() 메서드를 잠시 검토하세요.

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

    TillAmountSummary 메서드는 cashTill 배열을 사용하여 현금출납기에서 현재 사용할 수 있는 현금 금액을 계산합니다.

이제 기존 코드 프로젝트에 대한 검토가 끝났습니다.

MakeChange 배열을 사용할 때 testData가 현금을 성공적으로 관리하는지 확인합니다.

이 작업에서는 testData 배열을 사용하여 거래를 시뮬레이션하고 MakeChange가 현금출납기의 잔액을 성공적으로 관리하는지 확인합니다.

  1. Visual Studio Code 실행 메뉴에서 디버깅 시작을 선택합니다.

  2. IOException 오류가 발생합니다.

    디버그 콘솔은 Console.Clear() 또는 Console.ReadLine() 메서드를 지원하지 않습니다. 디버그하기 전에 launch.json 파일을 업데이트해야 합니다.

  3. 디버그 도구 모음에서 중지를 선택합니다.

  4. 탐색기 보기를 사용하여 launch.json 파일을 엽니다.

  5. launch.json 파일에서 다음과 같이 console 특성을 업데이트합니다.

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

    console 특성의 기본값은 internalConsole이며 디버그 콘솔 패널에 맞춰집니다. 아쉽게도 디버그 콘솔 패널은 일부 콘솔 메서드를 지원하지 않습니다. integratedTerminal 설정은 콘솔 입력 및 출력을 지원하는 터미널 패널에 맞춰집니다.

  6. launch.json 파일에 변경 내용을 저장합니다.

  7. Visual Studio Code 실행 메뉴에서 디버깅 시작을 선택합니다.

  8. 터미널 패널에서 애플리케이션에 의해 생성된 출력을 검토합니다.

    디버그 콘솔 패널에서 터미널 패널로 전환하여 출력을 검토합니다.

  9. MakeChange 배열을 사용하여 거래를 시뮬레이션할 때 testData가 현금출납기의 잔액을 성공적으로 관리합니다.

    보고된 출력의 맨 아래에 다음 줄이 나열됩니다.

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

    보고된 현금출납기 잔액과 예상 잔액은 모두 551입니다.

  10. 애플리케이션을 종료하려면 Enter 키를 누릅니다.

논리 문제 식별 및 수정

이 작업에서는 시뮬레이션된 거래를 사용하여 코드 논리 문제를 노출한 다음, Visual Studio Code 디버거 도구를 사용하여 문제를 격리하고 수정합니다.

  1. 임의로 생성된 거래를 사용하여 코드를 실행하려면 useTestData에 할당된 값을 false로 변경합니다.

    최상위 문의 윗부분에서 useTestData 변수를 찾을 수 있습니다.

  2. Program.cs 파일을 저장한 다음 디버거에서 애플리케이션을 실행합니다.

  3. 터미널 패널에서 출력을 검토합니다.

  4. 현금출납기 잔액이 일치하지 않습니다.

    MakeChange에 의해 계산된 최종 현금출납기 잔액과 최상위 문에 의해 유지되는 잔액은 출력의 맨 아래에 보고됩니다. 예를 들면 다음과 같습니다.

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

    참고

    애플리케이션은 구매 항목의 비용을 임의로 생성합니다. 따라서 출력에 보고된 현금출납기 잔액은 서로 다릅니다.

  5. 애플리케이션을 종료하려면 Enter 키를 누릅니다.

  6. 터미널 패널을 닫습니다.

코드 디버그

이 작업에서는 Visual Studio Code 디버거 도구를 사용하여 논리 문제를 격리하고 수정합니다.

  1. 최상위 문의 마지막 부분에서 다음 코드 줄을 찾아보세요.

    Console.WriteLine();
    
  2. 선택한 코드 줄에 중단점을 설정합니다.

  3. Visual Studio Code 실행 메뉴에서 디버깅 시작을 선택합니다.

  4. 코드 실행이 중단점에서 일시 중지됩니다.

  5. 디버그 컨트롤 도구 모음에서 단계별 진입을 선택합니다.

  6. 터미널 패널에서 출력을 검토합니다.

  7. 보고된 잔액과 예상된 잔액이 같으면 디버그 컨트롤 도구 모음에서 계속을 선택합니다.

  8. 보고된 잔액과 예상된 잔액 간의 불일치가 표시될 때까지 이전 단계를 반복합니다.

  9. 불일치가 표시되면 거래 세부 정보를 잠시 검토하세요.

  10. 보고된 수령한 현금과 반환한 거스름돈은 정확하지만 현금출납기는 5달러가 부족합니다.

    이 부족은 보고는 정확하더라도 cashTill 배열이 잘못 업데이트되고 있음을 시사합니다.

  11. 디버그 세션을 중지하고 터미널 패널을 닫습니다.

  12. MakeChange 메서드 맨 아래로 스크롤합니다.

    "변경을 가하는" 데 사용되는 while 문은 MakeChange 메서드의 끝에 있습니다.

  13. 변경을 수행하기 위해 사용되는 while 문 코드 블록을 검토합니다.

    현금출납기에 5달러가 부족하기 때문에 문제가 5달러 지폐를 반환하는 데 사용되는 while 코드 블록에 있을 가능성이 높습니다.

  14. 다음 코드를 확인합니다.

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

    cashTill[] 배열은 현재 사용할 수 있는 각 액면 금액의 지폐 수를 저장하는 데 사용됩니다. 배열 요소 1은 5달러 지폐 수를 관리하는 데 사용됩니다. while 문장의 식은 cashTill[1]을 올바르게 참조합니다. 그러나 코드 블록 내의 문은 cashTill[2]이 아닌 cashTill[1]를 감소시킵니다. 인덱스 값 2를 지정하면 현금출납기에서 5달러 지폐가 아닌 10달러 지폐가 제거됩니다.

  15. while 코드 블록을 다음과 같이 업데이트합니다.

    while ((changeNeeded > 4) && (cashTill[1] > 0))
    {
        cashTill[1]--;
        changeNeeded -= 5;
        Console.WriteLine("\t A five");
    }    
    
  16. Program.cs 파일을 저장합니다.

작업 확인

이 작업에서는 애플리케이션을 실행하고 업데이트된 코드가 의도한 대로 작동하는지 확인합니다.

  1. Visual Studio Code 실행 메뉴에서 모든 중단점 제거를 선택합니다.

  2. 실행 메뉴에서 디버깅 시작을 선택합니다.

  3. 터미널 패널에서 출력을 검토합니다.

  4. 보고된 금액이 예상된 금액과 같은지 확인합니다.

    MakeChange에 의해 계산된 최종 현금출납기 잔액과 최상위 문에 의해 유지되는 잔액은 출력의 맨 아래에 보고됩니다. 예를 들면 다음과 같습니다.

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

    애플리케이션은 구매 항목의 비용을 임의로 생성합니다. 따라서 출력에 보고된 현금출납기 잔액은 서로 다릅니다. 두 값이 같으면 성공적으로 논리 문제를 해결한 것입니다.