在测试中声明消息

再一次问好。“ C#开发人员”课程开始之前,我们已经翻译了有关测试中的断言消息的有趣材料,并很高兴与您共享翻译。




在这篇文章中,我们将讨论您是否应该在测试中使用Assert消息。

我从读者同事那里收到了一个有趣的问题,我想对其进行更详细的介绍:我有一个有关Assert消息的问题

我是否应该使用包含message参数的重载并使用它发送一个描述Assert失败原因的字符串(也称为“声明”) ?

这个问题的答案可以归结为两个方面:

  • 测试的可读性-了解测试的功能是多么容易。
  • 易于诊断-了解测试为什么失败很容易。

让我们分别讨论每个

测试可读性


人们经常使用断言消息来帮助团队成员和他们自己将来了解测试中正在发生的事情。让我们看下面的例子:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.AreEqual(UserType.Employee, person.Type); //  
    Assert.AreEqual(1, company.NumberOfEmployees); //  
}

您还可以指出测试Assert验证某些内容的原因,而不是仅仅使用Assert进行声明:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.AreEqual(UserType.Employee, person.Type, "Person must become an employee after hiring");
    Assert.AreEqual(1, company.NumberOfEmployees, "Number of employees must increase");
}

这样的陈述有帮助,但它们是有代价的。这些消息要求您

  • 花时间写他们
  • 让他们前进

这里的优缺点与代码注释相同。并且,就像在评论中一样,我建议您:不要仅仅出于可读性目的而编写断言消息。如果您觉得没有断言消息就无法进行测试,请尝试重构它。从长远来看,让测试自己说出来要比使其与断言消息保持同步要容易得多(这只是中断同步的时间问题)。

仅在绝对必要时(当您无法以其他任何方式提高测试的可读性时)输入断言消息。但是即使那样,还是倾向于选择不写它们。

快速获得测试可读性的最简单方法是切换到可读的语句记录。例如,NUnit有一个特殊的基于约束的语句模型,可以帮助您通过以下方式编写语句:

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    Assert.That(person.Type, Is.EqualTo(UserType.Employee));
    Assert.That(company.NumberOfEmployees, Is.EqualTo(1));
}

或者,您可以使用我最喜欢的Fluent断言

[Test]
public void Hiring_a_new_team_member()
{
    var company = new Company();
    var person = new Person(UserType.Customer);

    company.HireNewMember(person);

    person.Type.Should().Be(UserType.Employee);
    company.NumberOfEmployees.Should().Be(1);
}

这些语句以纯英语阅读-正是您希望阅读所有代码的方式。我们人类更喜欢以故事的形式来感知信息。所有故事都遵循此模型:

[] [] [].

例如,

  .

这里-主题,-动作和-对象。代码也一样。

这个版本

company.NumberOfEmployees.Should().Be(1);

阅读比

Assert.AreEqual(1, company.NumberOfEmployees);

正是因为这里有历史。
, . , .


断言消息的另一种观点是易于诊断。换句话说,无需检查该测试的代码即可轻松了解测试失败的原因。在读取CI装配结果时,这很有用。

从诊断的角度来看,请遵循本指南:如果您可以轻松地在本地重新启动测试,则此测试不需要断言消息。这适用于所有单元测试(因为它们不能与进程外依赖项一起工作),但对于集成和端到端测试而言则较小。


测试金字塔

随着您在测试金字塔中不断攀升,您可能需要更多详细信息,因为集成(尤其是端到端)测试速度较慢,并且您可能无法随意重新运行它们。

但是,即使使用集成和端到端测试,也有一些方法可以在不求助于断言消息的情况下促进诊断:

  • 使测试测试一个行为模块-当测试检查一件事时,通常很容易确定出了什么问题。(这并不总是适用于端到端测试,因为您可能希望这些测试检查行为的多个单元如何紧密协作)。
  • 相应地命名您的单元测试 -理想的测试名称以商业术语描述应用程序的行为,以便即使是非程序员也可以理解它。

并且不要忘记,即使没有用户声明,您仍然可以获得单元测试环境为您生成的消息。

例如,以下语句中的错误:

person.Type.Should().Be(UserType.Employee);

给出以下错误信息:

Xunit.Sdk.EqualException: Assert.Equal() Failure
Expected: Employee
Actual:   Customer

由环境生成的此类消息与人类可读的测试名称的组合,即使在易于诊断方面,也使90%的用户断言消息无用。唯一的例外是冗长的端到端测试。它们通常包含多阶段检查,因此可以使用其他断言消息来了解哪些步骤失败了。但是,不应有很多这样的端到端测试。

当然,为了利用框架生成的错误消息,您需要避免常见的布尔比较,例如:

(person.Type == UserType.Employee).Should().BeTrue();

因为它们导致以下错误消息:

Xunit.Sdk.TrueException: Assert.True() Failure
Expected: True
Actual:   False

这根本没有帮助诊断。

摘要


在撰写陈述时,您经常感到懒惰吗?好了,现在您可以为它辩护,并将您的同事发送给本文。


“开个

玩笑,我很高兴”,不过,这里有个总结:

  • 使用断言消息有两个方面:
    • 测试的可读性(了解测试的作用有多容易)。
    • 易于诊断(了解在CI生成期间测试为何失败的难易程度)。
  • 就测试的可读性而言,断言消息是代码注释。不必依赖它们,而是重构测试以实现可读性。
  • 在诊断方面,断言消息的最佳替代方法是:
    • 通过测试测试单个行为模块
    • 以业务术语命名测试
  • 唯一的例外是冗长的端到端测试。

就这样。您可以在今天举行免费网络研讨会上了解有关我们课程的更多信息

All Articles