Unit testing 在这个单元测试中是否有太多的断言?

Unit testing 在这个单元测试中是否有太多的断言?,unit-testing,assert,Unit Testing,Assert,在这个单元测试中是否有太多的断言 [Fact] public void Send_sends_an_email_message() { using (var server = new MockSmtpServer()) { server.Start(); using (var client = new EmailClient("localhost")) { string from = "john.doe@example.com";

在这个单元测试中是否有太多的断言

[Fact]
public void Send_sends_an_email_message() {
    using (var server = new MockSmtpServer()) {
        server.Start();
        using (var client = new EmailClient("localhost")) {
            string from = "john.doe@example.com";
            IEnumerable<string> to = new[] { "jane.doe@example.com" };
            string subject = "Test";
            string body = "Test.";
            client.Send(from, to, subject, body);
            var session = server.Sessions.FirstOrDefault();
            Assert.NotNull(session);
            var message = session.Messages.FirstOrDefault();
            Assert.NotNull(message);
            Assert.NotNull(message.From);
            Assert.Equal(message.From.Address, "john.doe@example.com");
            Assert.NotNull(message.To);
            var recipient = message.To.FirstOrDefault();
            Assert.NotNull(recipient);
            Assert.Equal(recipient.Address, "jane.doe@example.com");
            Assert.Equal(message.Subject, "Test");
            Assert.Equal(message.Body, "Test.");
        }
    }
}
[事实]
公共无效发送发送电子邮件消息(){
使用(var server=new MockSmtpServer()){
server.Start();
使用(var client=newemailclient(“localhost”)){
来自约翰的字符串。doe@example.com";
IEnumerable to=new[]{“jane”。doe@example.com" };
字符串subject=“Test”;
字符串体=“测试。”;
发送(发件人、收件人、主题、正文);
var session=server.Sessions.FirstOrDefault();
Assert.NotNull(会话);
var message=session.Messages.FirstOrDefault();
Assert.NotNull(消息);
Assert.NotNull(message.From);
Assert.Equal(message.From.Address,“john。doe@example.com");
Assert.NotNull(message.To);
var recipient=message.To.FirstOrDefault();
Assert.NotNull(接收方);
Assert.Equal(recipient.Address),jane。doe@example.com");
Assert.Equal(message.Subject,“Test”);
Assert.Equal(message.Body,“Test.”);
}
}
}

我认为这段代码不需要任何解释,但如果需要,请让我知道。

一般来说,断言越多越好。单元测试中的一个常见错误是不够明确

你的测试是非常明确和可读的。我特别喜欢null上的断言。这是一个很好的实践,因为它使解释测试失败变得非常简单


唯一能让你拥有太多断言的方法是,如果你多次断言同一件事,而你没有这样做。

我看你的断言没有什么特别的问题,但是如果你想清理你的代码,你可以改变

var session = server.Sessions.FirstOrDefault();
Assert.NotNull(session);
进入

First()。还有其他地方你也可以做类似的改变


但是作为一般规则,在单元测试中不要想当然——这意味着大量的断言

这取决于你所遵循的标准,但我通常会说是的,你在测试中的断言太多了


许多人主张一个测试应该有一个断言;我认为这可能有点过分,但我确实相信,对单个功能块进行单个单元测试是合适的;你到处都是你的财产。测试太大了;将它分解为几个不同的测试。

我尽量使我的单元测试保持相当小的规模,一次只测试一件事情。因此,我可能会将不同的测试部分分成不同的测试,例如

  • sendWillSendAnEmail
  • 来自containssenderaddress
  • 至ContainesRecipientAddress
  • mailBodyContainsMailMessage
  • mailcontainssObject

我认为问题是,assert()d值是否独立变化?如果它们独立地改变,那么它们应该在不同的测试中进行测试,这些测试会改变与每个断言相关的条件

但是,如果您有一个代码路径生成包含所有这些字段的电子邮件,那么在一个测试中测试所有这些内容是合适的


但是现在这个测试有点难读。您可能希望将这些断言包装在描述性帮助器方法中。在我发现同样的helper方法在其他地方可能有用之前,我不会为此烦恼。

我认为它太大了

当您有一组较小的测试时,您可以得到“缺陷定位”——只需运行所有测试,您就可以准确地看到问题所在。由于断言的数量与当前相同(并且没有断言消息),您可能需要启动调试器才能找到答案。请记住,您可能最终会有成百上千的测试,如果有一堆测试失败,您不希望必须调试每一个测试以了解原因


此外,任何在测试早期失败的断言都意味着后面的断言不会运行。当它们被分成单独的测试时,每个断言都会被检查。这是一种权衡;很多断言可能是相关的,并且会同时失败,因此您将有五个红色测试,而不是一个。但我的工作前提是信息越多越好,因此我宁愿进行这五次测试,并知道所有五次断言都失败。

您的许多断言语句表明您在单元测试中有多少逻辑。您必须像维护常规代码一样维护单元测试。与其编写单元测试代码,不如花时间进行防御性编程和契约式编程。

也许您可以创建一个新的电子邮件类,该类在其默认构造函数中接受所有这些参数

然后,您可以在用户传递无效参数时引发异常

在单元测试中

发送\u发送\u电子邮件\u消息

您可以添加仅检查等式的断言,而不是检查null


也许您可以在一个测试中创建两封电子邮件,并对两个实例进行相等断言。

是的,您的代码中断言太多了!此外,每个测试方法只能有一个assert语句。使用多个断言可能会让代码嗅到您正在测试不止一件事情。此外,有人可能会在测试中添加新的断言,而不是编写另一个断言。当第一个资产失败时,您如何理解您的其他资产是如何完成的


您可能也会发现这篇文章很有趣:

,但是您不是以大量重复代码或大量infrastructure-y代码来设置这些不同的测试吗?这真的值得吗?@Arlen:我的单元测试需要重复一些代码,但通过使用工厂方法进行测试设置和自定义断言方法,将这一点保持在最低限度。诀窍是最大限度地减少代码重复,以达到
var session = server.Sessions.First();