练习 - 使用示例数据评审和测试 C# 控制台应用程序
在本练习中,你将评审和测试 Starter 项目中的代码,查找并修复逻辑问题,然后验证更新后的应用程序是否按预期运行。
在本练习中,完成以下任务:
代码评审:评审 Program.cs 文件的内容。
Program.cs 包括以下代码部分:
- 顶级语句:顶级语句使用
testData数组或大量随机生成的交易来模拟一系列交易。 - LoadTillEachMorning:
LoadTillEachMorning方法用于配置收银机,其中每种面额都有预定义数量的钞票。 - MakeChange:
MakeChange方法用于在购买交易期间管理现金。 - LogTillStatus:
LogTillStatus方法用于显示当前收银机中每种面额的钞票数量。 - TillAmountSummary:
TillAmountSummary方法用于显示一条消息,以告知收银机中的现金金额。
- 顶级语句:顶级语句使用
初始测试:验证使用
MakeChange数组模拟交易时testData是否成功使收银机收支平衡。代码调试:查找并纠正使用随机生成的数据时出现的逻辑问题。
验证测试:对在本练习中开发的代码执行验证测试。
评审 Program.cs 文件的内容
在此任务中,你将完成 Starter 项目代码的演练。 Program.cs 文件包含一个模拟日常交易条件的应用程序。 该应用程序调用 MakeChange 方法在每个交易期间管理收银机。 其他方法用于初始化收银机和生成报告消息。
确保 GuidedProject 文件夹在 Visual Studio Code 中处于打开状态。
在“资源管理器”视图中,展开 GuidedProject 和 Starter 文件夹。
Starter 文件夹包含此指导式项目模块的示例应用程序。
在 Visual Studio Code 编辑器中打开 Program.cs 文件。
在“视图”菜单中,选择“命令面板”。
在命令提示符下,输入“.net: g”,然后选择“.NET:生成资产以进行生成和调试”。
在“选择要启动的项目”提示符下,选择 Starter 项目。
创建的 launch.json 文件将包含 Starter 项目的配置。
花几分钟时间查看此应用程序的顶级语句:
/* 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文件。- 配置用于测试
花点时间来查看
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]; }花几分钟来查看
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会返回一条描述性消息,并且交易取消。
花点时间来查看
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数组报告收银机的当前内容。花点时间来查看
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 是否成功使收银机收支平衡。
在 Visual Studio Code 的“运行”菜单上,选择“开始调试”。
请注意,出现了
IOException错误。调试控制台不支持
Console.Clear()或Console.ReadLine()方法。 你需要在调试前更新 launch.json 文件。在“调试”工具栏上,选择“停止”。
使用“资源管理器”视图打开 launch.json 文件。
在 launch.json 文件中,更新
console属性,如下所示:// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console":"integratedTerminal",console属性的默认值为internalConsole,与“调试控制台”面板一致。 遗憾的是,“调试控制台”面板不支持某些控制台方法。integratedTerminal设置支持控制台输入和输出,与“终端”面板一致。将更改保存到 launch.json 文件。
在 Visual Studio Code 的“运行”菜单上,选择“开始调试”。
在“终端”面板中查看应用程序生成的输出。
从“调试控制台”面板切换到“终端”面板以查看输出。
请注意,使用
MakeChange数组模拟交易时,testData成功使收银机收支平衡。在报告的输出底部,你应会看到以下几行:
The till has 551 dollars Expected till value: 551 Press the Enter key to exit请注意,报告的收银机值和预期的收银机值均为 551。
若要退出应用程序,请按 Enter。
确定并修复逻辑问题
在此任务中,你使用模拟交易来暴露代码逻辑问题,然后使用 Visual Studio Code 调试程序工具来查找和修复问题。
若要使用随机生成的交易运行代码,请将分配给
useTestData的值更改为false。你可以在顶级语句的顶部附近找到
useTestData变量。保存 Program.cs 文件,然后在调试程序中运行应用程序。
在“终端”面板中查看输出。
请注意收银机余额的出入。
输出的底部报告
MakeChange计算的最终收银机余额和顶层语句中保存的余额。 例如:Transaction successfully completed. The till has 379 dollars Expected till value: 434 Press the Enter key to exit注意
该应用程序随机生成所购商品的价格。 因此,输出中报告的收银机值是不同的。
若要退出应用程序,请按 Enter。
关闭“终端”面板。
调试代码
在此任务中,你使用 Visual Studio Code 调试程序工具查找和修复逻辑问题。
在顶级语句的末尾附近,找到以下代码行:
Console.WriteLine();在选定的代码行上设置断点。
在 Visual Studio Code 的“运行”菜单上,选择“开始调试”。
请注意,代码会在断点处暂停运行。
在“调试控件”工具栏上,选择“单步执行”。
在“终端”面板中查看输出。
如果报告的收银机值和预期的收银机值相等,请在“调试控件”工具栏上选择“继续”。
重复上一步,直到报告的收银机值和预期的收银机值之间存在出入。
发现出入后,请花一点时间查看交易的详细信息。
请注意,报告的所收现金和退还零钱是正确的,但收银机少了五美元。
这个缺额表明虽然报告是正确的,但
cashTill数组未正确更新。停止调试会话并关闭“终端”面板。
滚动到
MakeChange方法的底部。用于“找零”的
while语句位于MakeChange方法的末尾。查看用于找零的
while语句代码块。收银机少了五美元,问题很可能出在用于退还五美元钞票的
while代码块。请注意以下代码:
while ((changeNeeded > 4) && (cashTill[1] > 0)) { cashTill[2]--; changeNeeded -= 5; Console.WriteLine("\t A five"); }cashTill[]数组用于存储当前可用的每种面额的钞票数量。 数组元素1用于管理收银机中五美元钞票的数量。while语句中的表达式正确引用了cashTill[1]。 但是,代码块内的语句扣减了cashTill[2]而不是cashTill[1]。 指定索引值2表示从收银机中取出的是一张十美元的钞票,而不是一张五美元的钞票。按如下所示更新
while代码块:while ((changeNeeded > 4) && (cashTill[1] > 0)) { cashTill[1]--; changeNeeded -= 5; Console.WriteLine("\t A five"); }保存 Program.cs 文件。
检查你的工作
在此任务中,你运行应用程序并验证更新的代码是否按预期运行。
在 Visual Studio Code 的“运行”菜单上,选择“删除所有断点”。
在“运行”菜单上,选择“开始调试”。
在“终端”面板中查看输出。
验证报告的收银机值是否等于预期的收银机值:
输出的底部报告
MakeChange计算的最终收银机余额和顶层语句中保存的余额。 例如:Transaction successfully completed. The till has 452 dollars Expected till value: 452 Press the Enter key to exit该应用程序随机生成所购商品的价格。 因此,输出中报告的收银机值是不同的。 当这两个值相等,你就成功修复了逻辑问题。