使用C#,我需要一个名为User
的类,它有一个用户名,密码,活动标志,名字,姓氏,全名等。
应该有验证和保存用户的方法。我只是为这些方法编写测试吗?我甚至需要担心测试属性,因为它们是.Net的getter和setter?
答案 0 :(得分:130)
对此我也提出了很多好的回答:“Beginning TDD - Challenges? Solutions? Recommendations?”
我还建议看一下我的blog post(部分受我的问题启发),我对此有了一些很好的反馈。即:
我不知道从哪里开始?
- 重新开始。在编写新文章时,只考虑编写测试 码。这可以是旧的重新工作 代码或全新功能。
- 开始简单。不要跑掉,试图让你的头转 测试框架以及存在 TDD式的。 Debug.Assert工作正常。 用它作为起点。它没有 搞乱您的项目或创建 的依赖关系。
- 开始积极。你正在努力提高自己的技艺,感觉很好 它。我见过很多开发者 在那里很高兴停滞不前 而不是尝试更好的新事物 他们自己。你做得对 事情,记住这一点,它会有所帮助 阻止你放弃。
- 准备迎接挑战。很难开始进入 测试。期待挑战,但是 记住 - 可以克服挑战。
仅测试您的预期
我第一次遇到真正的问题 开始因为我经常坐着 那里试图找出每一个 可能发生的问题和 然后尝试测试并修复。 这是一个令人头痛的快速方法。 测试应该是真正的YAGNI 处理。如果你知道有一个 问题,然后为它写一个测试。 否则,不要打扰。
只测试一件事
每个测试用例都应该只进行测试 一件事。如果你发现自己 将“和”放在测试用例名称中, 你做错了什么。
我希望这意味着我们可以继续“吸气者和二传手”:)
答案 1 :(得分:62)
测试您的代码,而不是语言。
单位测试如:
Integer i = new Integer(7);
assert (i.instanceOf(integer));
仅在您编写编译器时非常有用,并且instanceof
方法不可能有效。
不要测试可依赖语言强制执行的内容。在您的情况下,我将专注于您的身份验证和保存方法 - 我会编写测试,确保他们可以优雅地处理任何或所有这些字段中的空值。
答案 2 :(得分:38)
这使我进入单元测试,这让我非常高兴
我们刚刚开始进行单元测试。 很长一段时间我都知道开始这样做会很好,但我不知道如何开始,更重要的是要测试什么。
然后我们必须在会计程序中重写一段重要的代码。 这部分非常复杂,因为它涉及很多不同的场景。 我正在谈论的部分是支付销售和/或购买已经输入会计系统的发票的方法。
我只是不知道如何开始编码,因为有很多不同的付款方式。 发票可能是100美元,但客户只转移了99美元。 也许您已将销售发票发送给客户,但您也已从该客户处购买。 所以你以300美元的价格卖掉了他,但是买了100美元。您可以期望您的客户支付200美元来结算余额。 如果您以500美元的价格出售但客户只需支付250美元,该怎么办?
所以我有一个非常复杂的问题需要解决,有很多可能性,一个场景可以完美地工作,但在其他类型的invocie /支付组合上会出错。
这是单位测试拯救的地方。
我开始编写(在测试代码中)一种方法来创建发票清单,包括销售和购买。 然后我写了第二种方法来创建实际付款。 通常,用户可以通过用户界面输入该信息。
然后我创建了第一个TestMethod,测试了一张非常简单的单一发票付款,没有任何付款折扣。 当银行付款保存到数据库时,系统中的所有操作都会发生。 如您所见,我创建了发票,创建了付款(银行交易)并将交易保存到磁盘。 在我的断言中,我把正确的数字放在银行交易和链接的发票中。 我会检查交易后的付款次数,付款金额,折扣金额和发票余额。
测试结束后,我会去数据库并仔细检查我的预期是否存在。
之后我编写了测试,我开始编写付款方式(BankHeader类的一部分)。 在编码中我只用代码来打扰第一次测试。我还没有想到其他更复杂的场景。
我运行了第一个测试,修复了一个小错误,直到我的测试通过。
然后我开始编写第二个测试,这次使用付款折扣。 在我编写测试后,我修改了付款方式以支持折扣。
在通过付款折扣测试正确性时,我还测试了简单付款。 当然,这两项测试都应该通过。
然后我逐步深入到更复杂的场景。
1)想一个新的场景
2)为该场景编写测试
3)运行该单个测试以查看它是否会通过
4)如果没有,我会调试并修改代码,直到它通过。
5)修改代码时,我继续运行所有测试
这就是我设法创建非常复杂的付款方式的方法。 没有单元测试,我不知道如何开始编码,问题似乎势不可挡。 通过测试,我可以从一个简单的方法开始,并逐步扩展它,保证更简单的方案仍然有效。
我确信使用单元测试可以节省我几天(或几周)的编码时间,并且或多或少地保证了我方法的正确性。
如果我后来想到一个新场景,我可以将它添加到测试中,看看它是否正常工作。 如果不是,我可以修改代码,但仍然确保其他方案仍然正常工作。 这将在维护和错误修复阶段节省数天和数天。
是的,即使经过测试的代码仍然存在错误,如果用户执行了您没有想到的事情或阻止他做的事情
以下是我为测试付款方式而创建的一些测试。
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);
}
答案 3 :(得分:13)
如果它们真的很琐碎,那就不要费心去测试了。例如,如果它们是这样实现的;
public class User
{
public string Username { get; set; }
public string Password { get; set; }
}
另一方面,如果你正在做一些聪明的事情(比如在getter / setter中加密和解密密码),那就给它一个测试。
答案 4 :(得分:10)
规则是你必须测试你写的每一条逻辑。如果你在getter和setter中实现了一些特定的功能,我认为它们值得测试。如果他们只为某些私有字段分配值,请不要打扰。
答案 5 :(得分:5)
这个问题似乎是一个问题,即人们在哪些方面对哪些方法进行测试以及哪些方法不合适。
用于价值分配的制定者和获取者已经创造了一致性和未来的增长,并预见到一段时间后,制定者/获取者可能演变成更复杂的操作。将这些方法的单元测试放在适当的位置是有意义的,也是为了保持一致性和未来的增长。
代码可靠性,尤其是在进行更改以添加其他功能时,是主要目标。我不知道有人因为在测试方法中包含了setter / getter而被解雇了,但是我确信有些人希望他们测试的方法最后他们知道或者可以回忆起简单的set / get包装但是没有更长的时间。
也许团队的另一名成员扩展了set / get方法,以包含现在需要测试但未创建测试的逻辑。但是现在你的代码正在调用这些方法而你并不知道它们已经改变并需要进行深入的测试,你在开发和QA中进行的测试不会触发缺陷,而是第一个真正的业务数据发布日确实会触发它。
两名队友现在将讨论谁丢球,未能在进行单位测试时进行单位测试,其中包括可能失败但未被单元测试覆盖的逻辑。如果测试是从第一天开始在简单的set / gets上实现的,那么最初编写set / gets的队友将有更容易的时间从这个干净中出来。
我的意见是浪费了几分钟&#34;通过单元测试覆盖所有方法的时间,即使是微不足道的,也可以节省数天的头痛,以及业务损失/声誉和失去某人的工作。
事实上你用单元测试包装琐碎的方法可能会被那个初级队友看到,当他们将琐碎的方法改为非平凡的方法并提示他们更新测试时,现在没有人遇到麻烦,因为达到生产所包含的缺陷。
我们编码的方式以及可以从我们的代码中看到的规则可以帮助其他人。
答案 6 :(得分:4)
另一个规范的答案。我相信,这来自罗恩杰弗里斯:
仅测试您要使用的代码。
答案 7 :(得分:3)
对于最终可能在工具包中或在开源类型的项目中的简单模块,您应该尽可能多地测试,包括琐碎的getter和setter。您需要记住的是,在编写特定模块时生成单元测试非常简单直接。添加getter和setter是最少的代码,可以毫不费力地处理。但是,一旦将代码放在更大的系统中,这种额外的工作可以保护您免受底层系统中的更改,例如基类中的类型更改。测试everthing是完成回归的最佳方法。
答案 8 :(得分:3)
测试样板代码是浪费时间,但正如Slavo所说,如果你为你的getter / setter添加副作用,那么你应该编写一个测试以配合该功能。
如果您正在进行测试驱动开发,则应首先编写合同(例如接口),然后编写测试以执行记录预期结果/行为的接口。 然后自行编写您的方法,而无需触及单元测试中的代码。最后,获取代码覆盖率工具并确保测试执行代码中的所有逻辑路径。
答案 9 :(得分:3)
你应该测试一切。现在你有吸气剂和二传手,但有一天你可能会稍微改变它们,可能会做验证或其他。你今天写的测试将在明天使用,以确保一切都像往常一样继续工作。 当你写测试时,你应该忘记诸如“现在它是微不足道的”之类的考虑因素。在敏捷或测试驱动的上下文中,您应该测试未来的重构。 另外,你是否尝试输入非常奇怪的值,如极长的字符串或其他“坏”内容?那么你应该......永远不要假设你的代码将来有多么糟糕。
一般来说,我发现编写广泛的用户测试是一方面的,令人筋疲力尽。另一方面,尽管它总能为您提供有关应用程序应如何工作的宝贵见解,并帮助您抛弃简单(和错误)的假设(例如:用户名的长度始终少于1000个字符)。
答案 10 :(得分:3)
除了设置私有字段之外没有额外行为的getter和setter等真正琐碎的代码是过度的测试。在3.0 C#中甚至有一些语法糖,编译器负责处理私有字段,因此你不必编程。
我通常会编写许多非常简单的测试来验证我期望从我的课程中获得的行为。即使是添加两个数字等简单的东西也是如此。我在编写一个简单的测试和编写一些代码行之间切换了很多。这样做的原因是我可以改变代码而不用担心我破坏了我没想过的东西。
答案 11 :(得分:2)
通常,当仅为某些值定义方法时,请测试上的值以及上可接受的边界的值。换句话说,确保你的方法完成了它应该做的事情,但没有更多。这很重要,因为当你要失败时,你想早点失败。
在继承层次结构中,请确保测试LSP合规性。
测试默认的getter和setter对我来说似乎没什么用,除非你打算稍后进行一些验证。
答案 12 :(得分:2)
为你的getter和setter编写单元测试没有坏处。现在,他们可能只是在幕后进行现场获取/设置,但将来您可能需要验证逻辑或需要测试的属性间依赖性。现在写它是比较容易的,当你想到它然后记得在那个时候来的时候改进它。
答案 13 :(得分:1)
就个人而言,我会“测试任何可以破坏的东西”,简单的吸气剂(甚至更好的汽车特性)也不会破坏。我从来没有一个简单的return语句失败,因此永远不会对它们进行测试。如果getter在其中有计算或其他形式的语句,我肯定会为它们添加测试。
我个人使用Moq作为模拟对象框架,然后验证我的对象以它应该的方式调用周围的对象。
答案 14 :(得分:1)
我理解敏捷开发环境中的单元测试,是的,你需要测试getter和setter(假设它们是公开可见的)。单元测试的整个概念是将软件单元(在这种情况下是一个类)测试为black box。由于getter和setter在外部可见,因此您需要测试它们以及Authenticate和Save。
答案 15 :(得分:1)
我们软件开发人员忘记了什么时候进行测试驱动开发是我们行动背后的目的。如果在生产代码已经到位后正在编写单元测试,则测试值会下降(但不会完全丢失)。
在单元测试的真正精神中,这些测试不主要用于“测试”我们的更多代码;或者获得90%-100%更好的代码覆盖率。这些都是首先编写测试的附带好处。最大的回报是,由于TDD的自然过程,我们的生产代码结束得更好。
为了更好地传达这一想法,以下内容可能有助于阅读:
The Flawed Theory of Unit Tests
Purposeful Software Development
如果我们认为编写更多单元测试的行为有助于我们获得更高质量的产品,那么我们可能会遇到Cargo Cult测试驱动开发。
答案 16 :(得分:1)
虽然可以正确猜测代码需要测试的位置,但我通常认为您需要使用指标来支持此猜测。我认为单元测试与代码覆盖率指标密切相关。
代码包含大量测试但是小覆盖范围尚未经过充分测试。也就是说,具有100%覆盖率但未测试边界和错误情况的代码也不是很好。
您需要在高覆盖率(最小90%)和可变输入数据之间取得平衡。
请记住测试“垃圾进入”!
此外,单元测试不是单元测试,除非它检查故障。没有断言或标有已知异常的单元测试只会测试代码在运行时不会死!
您需要设计测试,以便始终报告故障或意外/不需要的数据!
答案 17 :(得分:1)
我建议为Authenticate和Save方法编写多个测试。除了成功案例(提供所有参数,所有内容都拼写正确等)之外,最好还是对各种失败案例进行测试(参数不正确或缺失,如果适用,还有不可用的数据库连接等)。我建议Pragmatic Unit Testing in C# with NUnit作为参考。
正如其他人所说,除非你的getter和setter中有条件逻辑,否则getter和setter的单元测试都是过度的。
答案 18 :(得分:1)
规范的答案是“测试任何可能破坏的东西”。如果您确定属性不会破坏,请不要测试它们。
一旦发现某些东西已经破裂(你发现了一个bug),显然这意味着你需要对它进行测试。编写测试以重现错误,观察它失败,然后修复错误,然后观察测试通过。
答案 19 :(得分:1)
如果您认为它可以破解,请为它编写测试。我通常不测试setter / getter,但是让我说你为User.Name创建一个,它连接名字和姓氏,我会写一个测试,所以如果有人改变了姓氏和名字的顺序,至少他会知道他改变了经过测试的东西。
答案 20 :(得分:1)
我会为你编写代码的任何东西编写一个测试,可以在GUI界面之外测试。
通常,我编写的任何具有任何业务逻辑的逻辑都放在另一个层或业务逻辑层中。
然后为任何可以做某事的事情编写测试很容易。
首先,在“业务逻辑层”中为每个公共方法编写一个单元测试。
如果我有这样的课程:
public class AccountService
{
public void DebitAccount(int accountNumber, double amount)
{
}
public void CreditAccount(int accountNumber, double amount)
{
}
public void CloseAccount(int accountNumber)
{
}
}
在我编写任何知道我要执行这些操作的代码之前,我要做的第一件事就是开始编写单元测试。
[TestFixture]
public class AccountServiceTests
{
[Test]
public void DebitAccountTest()
{
}
[Test]
public void CreditAccountTest()
{
}
[Test]
public void CloseAccountTest()
{
}
}
编写测试以验证您编写的代码以执行某些操作。如果你迭代一堆东西,并改变它们中的每一个,那就写一个做同样事情的测试和断言实际发生的事情。
您可以采取许多其他方法,即“行为驱动开发”(BDD),这些方法更具参与性,而不是开始使用单元测试技能的好地方。
因此,故事的寓意是,测试任何你可能担心的事情,保持单元测试测试特定尺寸的东西,很多测试都很好。
将您的业务逻辑保留在用户界面层之外,以便您可以轻松地为它们编写测试,并且您会很好。
我建议TestDriven.Net或ReSharper,因为它们都可以轻松集成到Visual Studio中。
答案 21 :(得分:1)
我认为测试吸气剂和吸尘器是愚蠢的。当他们只做一个简单的操作时的setters。就个人而言,我不会编写复杂的单元测试来涵盖任何使用模式。我尝试编写足够的测试来确保我已经处理了正常的执行行为以及我能想到的错误情况。我将编写更多单元测试作为对bug报告的响应。我使用单元测试来确保代码满足要求并使将来的修改更容易。当我知道如果我破坏某些测试失败时,我觉得更愿意更改代码。
答案 22 :(得分:1)
即使获取/设置也会产生奇怪的后果,具体取决于它们的实现方式,因此应将它们视为方法。
这些测试的每个测试都需要为属性指定参数集,定义可接受和不可接受的属性,以确保调用以预期的方式返回/失败。
您还需要了解安全问题,例如SQL注入,并测试这些问题。
所以是的,你需要担心测试属性。
答案 23 :(得分:1)
不要测试明显工作(样板)代码。因此,如果您的setter和getter只是“propertyvalue = value”和“return propertyvalue”,那么测试它是没有意义的。
答案 24 :(得分:1)
理想情况下,在编写课程时,您可以完成单元测试。这就是您在使用测试驱动开发时的意图。在实现每个功能点时添加测试,确保通过测试覆盖边缘情况。
之后编写测试会更痛苦,但可行。
以下是我在你的位置所做的事情:
这应该为您提供一套很好的单元测试工具,可以作为抵消回归的良好缓冲。
这种方法的唯一问题是代码必须设计才能以这种方式进行测试。如果您在早期出现任何耦合错误,您将无法轻松获得高覆盖率。
这就是在编写代码之前编写测试非常重要的原因。它迫使你编写松散耦合的代码。
答案 25 :(得分:1)
您应该尽可能使用单元测试来测试“每个非平凡的代码块”。
如果您的属性微不足道并且不太可能有人会在其中引入错误,那么不对其进行单元测试应该是安全的。
您的Authenticate()和Save()方法看起来非常适合测试。
答案 26 :(得分:1)
我不会测试属性的实际设置。我会更关心消费者如何填充这些属性,以及他们填充的内容。通过任何测试,您必须权衡风险与测试的时间/成本。
答案 27 :(得分:1)
测试类应验证:
当然,如果getter和setter没有特殊的逻辑,那么Authenticate和Save方法的测试应该覆盖它们,否则应该写一个explict测试
答案 28 :(得分:1)
如果Authenticate和Save方法使用这些属性,那么您的测试将间接触及属性。只要这些属性只提供对数据的访问,就不需要进行显式测试(除非你要100%覆盖)。
答案 29 :(得分:1)
您必须使用UT覆盖类的每个方法的执行,并检查方法返回值。这包括getter和setter,特别是在成员(属性)是复杂类的情况下,这需要在初始化期间分配大量内存。例如用一些非常大的字符串调用setter(或者用希腊符号调用)并检查结果是否正确(不截断,编码很好e.t.c。)
如果简单的整数也适用 - 如果你传递long而不是整数会发生什么?这就是你写UT的原因:)
答案 30 :(得分:1)
我会测试你的吸气剂和制定者。根据编写代码的人,有些人会改变getter / setter方法的含义。我已经看到变量初始化和其他验证作为getter方法的一部分。为了测试这类事情,你需要明确地覆盖该代码的单元测试。
答案 31 :(得分:0)
我第二次测试任何可能破坏的内容和不写愚蠢的测试。但最重要的原则是测试你发现的任何破坏:如果某些方法行为奇怪地写一个测试来概述使其失败的数据集,那么纠正错误并观察栏变绿。还要测试“边界”数据值(null,0,MAX_INT,空列表等)。
答案 32 :(得分:0)
在编写单元测试或任何测试时,您可以通过查看正在测试的边界条件来确定要测试的内容。例如,您有一个名为is_prime的函数。幸运的是,它完成了它的名字所暗示的并告诉你整数对象是否是素数。为此我假设你正在使用对象。现在,我们需要检查已知范围的素数和非素数对象的有效结果。那是你的出发点。
基本上,看一下函数,方法,程序或脚本应该发生什么,然后用相同的代码确定不应该发生什么。这是您测试的基础。随着您对代码中 应该 的更多了解,请准备好修改您的测试。
答案 33 :(得分:0)
编写没有价值的代码总是一个坏主意。由于建议的测试不会为您的项目增加任何价值(或非常接近它)。那么你就浪费了宝贵的时间,可以花时间编写真正带来价值的代码。
答案 34 :(得分:0)
我见过的最好的经验法则是一目了然地测试一下你无法分辨出来的东西,肯定会正常工作。还有更多,你最终测试语言/环境。
答案 35 :(得分:-3)
我不能特别谈论C#,但是当我编写单元测试时,我会测试每个输入,即使用户没有这样做,这样我知道如何防止自己的错误。