xunit 中的异常消息包含参数,因此我的测试失败

Exception message in xunit includes parameter so my test fails

我正在尝试检查我抛出的 异常是否给出了正确的错误消息。

我在 class 中有一个方法可以从值中提取(减去)。如果值小于 0,我将抛出异常。

if (amount < 0)
{
    throw new System.ArgumentOutOfRangeException("amount", AmountLessThanZeroMessage);
}

这是我的错误信息:

public const string AmountLessThanZeroMessage = "Amount is less than zero";

但是,当我尝试编写单元测试以查看是否收到正确的消息时,由于参数的原因,它失败了。这是测试:

[Fact]
public void CannotWithdrawLessThanZero()
{
    // Arrange
    var account = new Account("User", 23);

    // Act
    account.DepositCash(100);
    var thrownException = Assert.Throws<ArgumentOutOfRangeException>(() => account.WithdrawCash(-10));

    // Assert
    Assert.Equal(Account.AmountLessThanZeroMessage, thrownException.Message);
}

结果最后包含参数,导致测试失败:

实际消息似乎包括它引用的参数。我该如何更正此消息?我应该只将行 (Parameter 'amount') 添加到预期的字符串中,还是有更好的选择?

您可以创建完全相同的异常并使用其消息 属性。喜欢下面的代码

[Fact]
public void CannotWithdrawLessThanZero()
{
    // Arrange
    var account = new Account("User", 23);
    var expectedException = new System.ArgumentOutOfRangeException("amount", AmountLessThanZeroMessage);

    // Act
    account.DepositCash(100);
    var thrownException = Assert.Throws<ArgumentOutOfRangeException>(() => account.WithdrawCash(-10));

    // Assert
    Assert.Equal(expectedException.Message, thrownException.Message);
}

消息经常变化,消息可以本地化,所以测试消息相等性会使测试更脆弱。
相反,您可以测试是否抛出了正确的异常类型,或者甚至更好地创建特定于域的异常以确保出于正确的原因抛出了异常。

public class WithdrawOfNegativeAmountNotAllowedException : Exception
{
    public WithdrawOfNegativeAmountNotAllowedException(int amount) 
        : base($"Amount is less than zero ({amount})")
    {
    }
}

[Fact]
public void Cannot_withdraw_less_than_zero()
{
    var account = new Account("User", 23);
    account.DepositCash(100);

    Action withdraw = () => account.WithdrawCash(-10);

    withdraw.Should().Throw<WithdrawOfNegativeAmountNotAllowedException>();
}

以防您仍想测试消息是否正确。字符串的断言可以通过多种方式完成,我建议断言尽可能松散。
测试不太可能改变的消息部分。例如测试消息以某些文本开头或包含临界值。

[Fact]
public void Cannot_withdraw_less_than_zero()
{
    var account = new Account("User", 23);
    account.DepositCash(100);

    Action withdraw = () => account.WithdrawCash(-10);

    withdraw.Should()
        .Throw<WithdrawOfNegativeAmountNotAllowedException>()
        .And
        .Message.Should().ContainEquivalentOf("Amount is less than zero");
}