it-swarm.cn

在编写单元测试时,您如何知道要测试什么?

使用C#,我需要一个名为User的类,它有一个用户名,密码,活动标志,名字,姓氏,全名等。

应该有 验证 保存 用户的方法。我只是为这些方法编写测试吗?我甚至需要担心测试属性,因为它们是.Net的getter和setter?

126
Mike Roosa

对此的许多好的回应也在我的问题上:“ 开始TDD - 挑战?解决方案?建议?

我还建议看看我的 博客文章 (这部分灵感来自我的问题),我得到了一些很好的反馈。即:

我不知道从哪里开始?

  • 重新开始。在编写新代码时,只考虑编写测试。这可以重新处理旧代码或全新功能。
  • 从简单开始。不要试图让你的头围绕测试框架以及TDD-esque。 Debug.Assert工作正常。用它作为起点。它不会弄乱您的项目或创建依赖项。
  • 开始积极。你正在努力提高你的技艺,感觉很好。我看到很多开发人员都乐于停滞不前,而不是尝试新事物来改善自己。你正在做正确的事,记住这一点,这将有助于阻止你放弃。
  • 准备迎接挑战。开始进入测试非常困难。期待挑战,但请记住 - 挑战可以克服。

只测试您的期望

我刚开始时遇到了真正的问题,因为我经常坐在那里试图找出可能发生的每一个可能的问题,然后尝试测试并修复。这是一个令人头痛的快速方法。测试应该是真正的YAGNI过程。如果您知道存在问题,请为其编写测试。否则,不要打扰。

只测试一件事

每个测试用例应该只测试一件事。如果您发现自己将“和”放在测试用例名称中,那么您做错了什么。

我希望这意味着我们可以继续“吸气者和安装者”:)

129
Rob Cooper

测试你的代码,而不是语言。

单元测试如:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

只有在编写编译器时才有用,并且instanceof方法不可行的可能性非零。

不要测试可以依赖语言强制执行的东西。在您的情况下,我将专注于您的身份验证和保存方法 - 我会编写测试,确保他们可以优雅地处理任何或所有这些字段中的空值。

62
Tim Howland

这让我进入了单元测试,它让我很开心

我们刚刚开始进行单元测试。很长一段时间我都知道开始这样做会很好,但我不知道如何开始,更重要的是要测试什么。

然后我们不得不在会计程序中重写一段重要的代码。这部分非常复杂,因为它涉及很多不同的场景。我正在讨论的部分是支付已经输入会计系统的销售和/或购买发票的方法。

我只是不知道如何开始编码,因为有很多不同的付款方式。发票可能是100美元,但客户只转移了99美元。也许您已将销售发票发送给客户,但您也已从该客户处购买。所以你以300美元的价格卖掉了他,但是买了100美元。您可以期望您的客户支付200美元来结算余额。如果您以500美元的价格出售但客户只需支付250美元,该怎么办?

所以我有一个非常复杂的问题要解决,有很多可能性,一个场景可以完美地工作,但在其他类型的invocie /支付组合上会出错。

这是单元测试来救援的地方。

我开始编写(在测试代码中)一种方法来创建发票清单,包括销售和购买。然后我写了第二种方法来创建实际付款。通常,用户将通过用户界面输入该信息。

然后我创建了第一个TestMethod,测试一个非常简单的单一发票支付,没有任何付款折扣。当银行付款保存到数据库时,系统中的所有操作都会发生。如您所见,我创建了发票,创建了付款(银行交易)并将交易保存到磁盘。在我的断言中,我把正确的数字放在银行交易和链接的发票中。我在交易后检查付款数量,付款金额,折扣金额和发票余额。

测试运行后,我会去数据库并仔细检查我的预期是否存在。

之后 我写了测试,我开始编写支付方法(BankHeader类的一部分)。在编码中我只用代码来打扰第一次测试。我还没有考虑其他更复杂的场景。

我运行了第一个测试,修复了一个小bug,直到我的测试通过。

然后我开始编写第二个测试,这次是支付折扣。在我编写测试后,我修改了付款方式以支持折扣。

在通过付款折扣测试正确性的同时,我还测试了简单付款。两个测试当然都应该通过。

然后我逐渐走向更复杂的场景。

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);
    }
38
eroijen

如果他们真的很琐碎,那就不要费心去测试了。例如,如果它们是这样实现的;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

另一方面,如果你正在做一些聪明的事情(比如在getter/setter中加密和解密密码)那么就给它一个测试。

13
Steve Cooper

规则是你必须测试你编写的每一个逻辑。如果你在getter和setter中实现了一些特定的功能,我认为它们值得测试。如果他们只为某些私有字段分配值,请不要打扰。

10
Slavo

这个问题似乎是一个问题,即人们在哪些方面对哪些方法进行测试以及哪些不进行测试。

用于价值分配的制定者和获取者已经创建了一致性和未来的增长,并预见到一段时间后,二传手/吸气剂可能演变成更复杂的操作。将这些方法的单元测试放在适当的位置是有意义的,也是为了保持一致性和未来的增长。

代码可靠性,尤其是在进行更改以添加附加功能时,是主要目标。我不知道有人因为在测试方法中包含了setter/getter而被解雇了,但是我确信有些人希望他们测试的方法最后他们知道或者可以回忆起简单的set/get包装但是没有更长的时间。

也许团队的另一个成员扩展了set/get方法,以包含现在需要测试但之后没有创建测试的逻辑。但是现在你的代码正在调用这些方法而你并不知道它们已经改变并且需要深入测试,而你在开发和QA中进行的测试不会触发缺陷,但是在发布的第一天真正的业务数据确实存在触发它。

这两位队友现在将讨论谁丢球并且未能在进行单位测试时进行单位测试,其中包括可能失败但未被单元测试覆盖的逻辑。如果测试是从第一天开始在简单的set/gets上实现的,那么最初编写set/gets的队友将有更容易的时间从这个干净中出来。

我的观点是,用单元测试覆盖所有方法的几分钟“浪费”时间,即使是微不足道的,也可以节省几天的头痛,以及业务损失/声誉和失去某人的工作。

事实上,当你将琐碎的方法改为非平凡的方法并提示他们更新测试时,你确实用单元测试包装琐碎的方法可能会被那个初级队友看到,现在没有人因为缺陷被包含而遇到麻烦从达到生产。

我们编码的方式以及可以从代码中看到的规则可以帮助其他人。

5
Thomas Carlisle

另一个规范的答案。我相信,这来自Ron Jeffries:

仅测试您要使用的代码。

4
user9397

真正琐碎的代码,比如getters和setter,没有比设置私有字段更多的行为,这些代码都是过度的测试。在3.0 C#甚至有一些语法糖,编译器负责私有字段,所以你不必编程。

我经常写很多非常简单的测试来验证我期望从我的课程中获得的行为。即使是添加两个数字等简单的东西也是如此。我在编写一个简单的测试和编写一些代码行之间切换了很多。这样做的原因是我可以改变代码而不用担心我破坏了我没想过的东西。

3
Mendelt

你应该测试一切。现在你有吸气剂和二传手,但有一天你可能会稍微改变它们,可能会做验证或其他。你今天写的测试将在明天使用,以确保一切都像往常一样继续工作。当你写测试时,你应该忘记诸如“现在它是微不足道的”之类的考虑因素。在敏捷或测试驱动的上下文中,您应该测试未来的重构。另外,你是否尝试输入非常奇怪的值,如极长的字符串或其他“坏”内容?那么你应该......永远不要假设你的代码将来会被滥用得多么糟糕。

一般来说,我发现编写广泛的用户测试是一方面的,令人筋疲力尽。另一方面,尽管它总能为您提供有关应用程序应如何工作的宝贵见解,并帮助您抛弃简单(和错误)的假设(例如:用户名的长度始终小于1000个字符)。

3
Sklivvz

对于最终可能在工具包中或在开源类型的项目中的简单模块,您应该尽可能多地测试,包括琐碎的getter和setter。您需要记住的是,在编写特定模块时生成单元测试非常简单直接。添加getter和setter是最少的代码,可以毫不费力地处理。但是,一旦将代码放在更大的系统中,这种额外的工作可以保护您免受底层系统中的更改,例如基类中的类型更改。测试everthing是完成回归的最佳方法。

3
Dirigible

测试样板代码是浪费时间,但正如Slavo所说,如果你为你的getter/setter添加副作用,那么你应该编写一个测试来配合该功能。

如果您正在进行测试驱动开发,则应首先编写合同(例如接口),然后编写测试以执行记录预期结果/行为的接口。 然后 自己编写方法,而不触及单元测试中的代码。最后,获取代码覆盖率工具并确保测试执行代码中的所有逻辑路径。

3
warren_s

通常,当仅为某些值定义方法时,在 和over 可接受的边界上测试值。换句话说,确保你的方法完成它应该做的事情, 但仅此而已 。这很重要,因为当你要失败时,你想早点失败。

在继承层次结构中,请确保测试 _ lsp _ compliance。

测试默认的getter和setter对我来说似乎没什么用,除非你打算稍后进行一些验证。

2
Rik

为getter和setter编写单元测试并没有什么坏处。现在,他们可能只是在幕后进行现场获取/设置,但将来您可能需要验证逻辑或需要测试的属性间依赖性。现在写它是比较容易的,当你想到它然后记得在那个时候到来时改进它。

2
Bob King

理想情况下,在编写课程时,您可以完成单元测试。这就是您在使用测试驱动开发时的意图。您在实现每个功能点时添加测试,确保您也通过测试覆盖Edge-cases。

之后编写测试会更痛苦,但可行。

这就是我在你的职位上做的事情:

  1. 编写一组测试核心功能的基本测试。
  2. 获取NCover并在测试中运行它。此时您的测试覆盖率可能约为50%。
  3. 继续添加覆盖Edge-cases的测试,直到覆盖率达到80%-90%左右

这应该为您提供一套良好的单元测试工具,可以作为抵消回归的良好缓冲。

这种方法的唯一问题是代码必须是 设计 以这种方式可测试。如果您在早期出现任何耦合错误,您将无法轻松获得高覆盖率。

这就是在编写代码之前编写测试非常重要的原因。它迫使你编写松散耦合的代码。

1
Simon Johnson

它使我们的代码更好......期间!

有些事情我们软件开发人员忘记了何时进行测试驱动开发是我们行动背后的目的。如果在生产代码已经到位后正在编写单元测试,则测试值会下降(但不会完全丢失)。

在单元测试的真正精神中,这些测试是 not 主要用于“测试”更多的代码;或者获得90%-100%更好的代码覆盖率。这些都是 附带好处 首先编写测试。最大的回报是,由于TDD的自然过程,我们的生产代码结束得更好。

为了更好地传达这一想法,以下内容可能有助于阅读:

单元测试的缺陷理论
有目的的软件开发

如果我们觉得写作的行为 更多的单元测试 是什么有助于我们获得更高质量的产品,那么我们可能会遭受 Cargo Cult 测试驱动开发。

1
Scott Saad

不要测试明显工作(样板)代码。因此,如果您的setter和getter只是“propertyvalue = value”和“return propertyvalue”,那么测试它是没有意义的。

1
erlando

即使获取/设置也会产生奇怪的后果,具体取决于它们的实现方式,因此应将它们视为方法。

这些测试的每个测试都需要为属性指定参数集,定义可接受和不可接受的属性,以确保调用以预期方式返回/失败。

您还需要了解安全问题,作为示例SQL注入,并测试这些问题。

所以,是的,你需要担心测试属性。

1
CestLaGalere

我相信当他们只做一个简单的操作时测试吸气剂和制定者是愚蠢的。就个人而言,我不会编写复杂的单元测试来涵盖任何使用模式。我尝试编写足够的测试来确保我已经处理了正常的执行行为以及我能想到的错误情况。我将编写更多单元测试作为对bug报告的响应。我使用单元测试来确保代码满足要求并使将来的修改更容易。当我知道如果我破坏某些测试失败时,我觉得更愿意更改代码。

1
Andrei Savu

好吧,如果你认为它可以打破,为它写一个测试。我通常不测试setter/getter,但是让我说你为User.Name创建一个,它连接名字和姓氏,我会写一个测试,所以如果有人改变了姓氏和名字的顺序,至少他会知道他改变了经过测试的东西。

1
pmlarocque

规范的答案是“测试任何可能破坏的东西”。如果您确定属性不会中断,请不要测试它们。

一旦发现某些东西已经破裂(你发现了一个bug),显然这意味着你需要对它进行测试。编写测试以重现错误,观察它失败,然后修复错误,然后观察测试通过。

1
Eric Normand

虽然可以正确猜出您的代码需要测试的位置,但我通常认为您需要使用指标来备份此猜测。我认为单元测试与代码覆盖度量标准密切相关。

代码有很多测试但是小覆盖率尚未经过充分测试。也就是说,具有100%覆盖率但未测试边界和错误情况的代码也不是很好。

您需要在高覆盖率(最小90%)和可变输入数据之间取得平衡。

记得测试“垃圾进去”!

此外,单元测试不是单元测试,除非它检查故障。没有断言或标有已知异常的单元测试只会测试代码在运行时不会死!

您需要设计测试,以便始终报告故障或意外/不需要的数据!

1
Ray Hayes

我会为你编写代码的任何东西写一个测试,这个代码在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.NetReSharper 可以轻松集成到Visual Studio中。

1
Dean Poulin

据我所知,在敏捷开发的背景下进行单元测试,是的,你需要测试getter和setter(假设它们是公开可见的)。单元测试的整个概念是测试软件单元,在这种情况下是一个类,作为 黑盒子 。由于getter和setter在外部可见,因此您需要测试它们以及Authenticate和Save。

1
Onorio Catenacci

如果Authenticate和Save方法使用这些属性,那么您的测试将间接触及属性。只要属性只提供对数据的访问,就不需要进行显式测试(除非您要进行100%的覆盖)。

1
Tom Walker

我会测试你的吸气剂和制定者。根据编写代码的人,有些人会改变getter/setter方法的含义。我已经看到变量初始化和其他验证作为getter方法的一部分。为了测试这种事情,你需要明确地覆盖该代码的单元测试。

1
Peter Bernier

就个人而言,我会“测试任何可以破坏的东西”,简单的吸气剂(甚至更好的汽车特性)也不会破坏。我从来没有一个简单的return语句失败,因此永远不会对它们进行测试。如果getter在其中有计算或其他形式的语句,我肯定会为它们添加测试。

我个人使用 Moq 作为模拟对象框架,然后验证我的对象以它应该的方式调用周围的对象。

1
tronda

您必须使用UT覆盖类的每个方法的执行,并检查方法返回值。这包括getter和setter,特别是在成员(属性)是复杂类的情况下,这需要在初始化期间分配大量内存。例如,用一些非常大的字符串(或带有希腊符号的东西)调用setter并检查结果是否正确(不截断,编码很好e.t.c.)

如果简单的整数也适用 - 如果你传递long而不是整数会发生什么?这就是你写UT的原因:)

1
m_pGladiator

测试类应该验证:

  1. 方法和属性返回预期值
  2. 当提供无效参数时,抛出适当的例外
  3. 当调用给定方法时,类和其他对象之间的交互按预期发生

当然,如果getter和setter没有特殊的逻辑,那么Authenticate和Save方法的测试应该覆盖它们,否则应该写一个explict测试

1
Crippledsmurf

我建议为Authenticate和Save方法编写多个测试。除了成功案例(提供所有参数,所有内容都拼写正确等)之外,最好还是对各种失败案例进行测试(参数不正确或缺失,如果适用,还有不可用的数据库连接等)。我推荐 使用NUnit在C#中进行语用单元测试 作为参考。

正如其他人所说,除非你的getter和setter中有条件逻辑,否则getter和setter的单元测试都是过度的。

1
Scott Lawrence

我不会测试属性的实际设置。我会更关心消费者如何填充这些属性,以及他们填充的内容。通过任何测试,您必须权衡风险与测试的时间/成本。

1
Bloodhound

您应该尽可能使用单元测试来测试“每个非平凡的代码块”。

如果您的属性微不足道并且不太可能有人会在其中引入错误,那么不对其进行单元测试应该是安全的。

您的Authenticate()和Save()方法看起来很适合测试。

1
user7015

编写没有价值的代码总是一个坏主意。由于建议的测试不会为您的项目增加任何价值(或非常接近它)。然后你浪费宝贵的时间,你可以花时间编写实际带来价值的代码。

0
pjesi

我第二次测试任何可能破坏的东西不要写愚蠢的测试。但最重要的原则是测试你发现的任何东西都被破坏了:如果某些方法表现得很奇怪,可以写一个测试来勾勒出使其失败的数据集,然后纠正错误并观察栏变为绿色。还测试“边界”数据值(null,0,MAX_INT,空列表等)。

0
Manrico Corazzi

在编写单元测试或任何测试时,您可以通过查看正在测试的边界条件来确定要测试的内容。例如,您有一个名为is_prime的函数。幸运的是,它完成了它的名字所暗示的并告诉你整数对象是否是素数。为此我假设你正在使用对象。现在,我们需要检查已知范围的素数和非素数对象的有效结果。那是你的出发点。

基本上,看一下函数,方法,程序或脚本应该发生什么,然后看看应该用相同的代码确定发生什么。这是您测试的基础。只要准备好修改你的测试,你就会更加了解你的代码会发生什么 should

0
Dan

我见过的最好的经验法则是一目了然地测试你无法分辨的所有东西,确定它们能正常工作。还有更多,你最终测试语言/环境。

0
user74754