c# - Assert.Throws 方法未捕获预期的异常

标签 c# nunit

我正在尝试测试一个非常简单的函数。它返回包含一些指定数字的数字。如果第一个参数是 null,它会抛出 ArgumentNullException

不幸的是,Assert.Throws 说,没有抛出预期的异常并且测试失败。当我尝试调试测试时,它不会进入我的方法。 ArgumentException 也是如此。

只有最后两个测试失败,其他测试成功。

我要测试的功能:

    /// <summary>
    /// Filter given numbers and return only numbers containing the specified digit.
    /// </summary>
    /// <param name="numbers">The numbers to be filtered.</param>
    /// <param name="digit">The digit which should be found.</param>
    /// <returns>Numbers that contains the digit.</returns>
    /// <exception cref="ArgumentException"> Thrown if the digit value isn't between 0 and 9.</exception>
    /// <exception cref="ArgumentNullException"> Thrown if numbers are null.</exception>
    public static IEnumerable<int> FilterDigits(IEnumerable<int> numbers, byte digit)
    {
        if (numbers == null)
        {
            throw new ArgumentNullException();
        }

        foreach (int number in numbers)
        {
            if (number.ContainsDigit(digit))
            {
                yield return number;
            }
        }
    }

    /// <summary>
    /// Check whether the number contains the given digit.
    /// </summary>
    /// <param name="number">The number which can contain the digit.</param>
    /// <param name="digit">The digit to be found.</param>
    /// <returns>True if the number contains the digit, else false.</returns>
    /// <exception cref="ArgumentException"> Thrown if the digit value isn't between 0 and 9.</exception>
    /// <example> ContainsDigit(10, 1) -> true </example>
    /// <example> ContainsDigit(10, 2) -> false </example>
    private static bool ContainsDigit(this int number, byte digit)
    {
        if (!char.TryParse(digit.ToString(), out char digitChar))
        {
            throw new ArgumentException("The digit should be from 0 to 9.");
        }

        string numberString = number.ToString();

        foreach (char ch in numberString)
        {
            if (ch == digitChar)
            {
                return true;
            }
        }

        return false;
    }

我的测试类:

[TestFixture]
public class DigitsFilterTests
{
    [TestCase(new int[] { 1, 4, 23, 346, 7, 23, 87, 71, 77 }, 7, ExpectedResult = new int[] { 7, 87, 71, 77 })]
    [TestCase(new int[] { 345, 4, 0, 90, 709 }, 0, ExpectedResult = new int[] { 0, 90, 709})]
    public IEnumerable<int> FilterDigits_NumbersContainDigit(int[] numbers, byte digit)
        => DigitsFilter.FilterDigits(numbers, digit);

    [TestCase(new int[] { 1, 4, 222, 9302 }, 7, ExpectedResult = new int[] { })]
    [TestCase(new int[] { 345, 4, 354, 25, 5 }, 0, ExpectedResult = new int[] { })]
    public IEnumerable<int> FilterDigits_NumbersNotContainDigit(int[] numbers, byte digit)
        => DigitsFilter.FilterDigits(numbers, digit);

    [TestCase(new int[] { }, 0, ExpectedResult = new int[] { })]
    public IEnumerable<int> FilterDigits_EmptyList(int[] numbers, byte digit)
        => DigitsFilter.FilterDigits(numbers, digit);

    [Test]
    public void FilterDigits_NullNumbers_ArgumentNullException()
        => Assert.Throws<ArgumentNullException>(() => DigitsFilter.FilterDigits(null, 5));

    [Test]
    public void FilterDigits_InvalidDigit_ArgumentException()
        => Assert.Throws<ArgumentException>(() => DigitsFilter.FilterDigits(new int[] { }, 10));
}

最佳答案

您的方法是使用 yield return 构建的可枚举方法。它的棘手之处在于,除非您列举它,否则实际上什么都不会发生

所以你必须确保你的测试枚举了内容:

    [Test]
    public void FilterDigits_NullNumbers_ArgumentNullException()
        => Assert.Throws<ArgumentNullException>(() => DigitsFilter.FilterDigits(null, 5).ToList());

此外,如果 numbers 为空,您的第二个测试将失败,因为您将无法访问 ContainsDigit

如果你想修复方法内部的行为,你需要把它分成两部分:

public static IEnumerable<int> FilterDigits(IEnumerable<int> numbers, byte digit)
{
    if (numbers == null)
    {
        throw new ArgumentNullException();
    }

    return FilterDigitsImpl(numbers, digit);
}

private static IEnumerable<int> FilterDigitsImpl(IEnumerable<int> numbers, byte digit)
{
    foreach (int number in numbers)
    {
        if (number.ContainsDigit(digit))
        {
            yield return number;
        }
    }
}

如果您的 C# 版本足够新,您可以使用本地函数合并这两种方法:

public static IEnumerable<int> FilterDigits(IEnumerable<int> numbers, byte digit)
{
    if (numbers == null)
    {
        throw new ArgumentNullException();
    }

    IEnumerable<int> FilterDigitsImpl()
    {
        foreach (int number in numbers)
        {
            if (number.ContainsDigit(digit))
            {
                yield return number;
            }
        }
    }

    return FilterDigitsImpl();
}

关于c# - Assert.Throws 方法未捕获预期的异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55317634/

相关文章:

c# - 如何用一个接口(interface)测试不同的类?

Selenium 网格用完可用插槽

c# - 如何在 Nhibernate 中连接两个表

c# - Identity Server 4 使用 IConfiguration 创建客户端

c# - MessageBoxIcon.Exclamation 和 MessageBoxIcon.Warning 有什么区别?

nunit - 在 CruiseControl.NET 中显示 NUnit 控制台输出

c# - 断言模拟对象构造函数抛出的异常

c# - 使用 Specflow 和 NUnit 版本 3 并行运行测试

C# 需要解释涉及类之外的变量的事情

c# - 使用超时循环将数据加载到 iframe 的更好选择