首页 > 解决方案 > 集合上的单元测试理论 xUnit

问题描述

原始问题

假设我有一个类方法GetAge(DateTime dateOfBirth),我想测试出来的年龄是否正确。为此,我创建了一个名为的辅助方法GenerateDateOfBirth(int age),该方法返回应产生年龄的出生日期age

但是,我不知道我的GenerateDateOfBirth方法是否有效,因此我想批量测试要输入的年龄集合GenerateDateOfBirth,其中每个生成的出生日期在输入时都应该产生原始年龄GetAge,类似于:

[Fact]
public void CrossTestGetAgeAndGenerateDateOfBirth()
{
    var ages = new List<int>(); // A reasonably large list of possible ages
    var rng = new Random();
    for (int i = 0; i < 1_000_000; i++)
    {
        ages.Add(rng.Next(0, 1000)); // Arbitrary upper bound on a person's age
    }
    foreach (var realAge in ages)
    {
        var dateOfBirth = GenerateDateOfBirth(realAge);
        var calculatedAge = GetAge(dateOfBirth);
        Assert.Equal(realAge, calculatedAge); // If false, at least one of the methods is bugged
    }
}

我已经看到 xUnit 允许通过使用 和 等属性对数据进行测试InlineDataMemberData所以我想知道是否可以生成一个整数列表,然后对所有“年龄”值进行数据驱动测试,如下所示:

public List<int> Ages { get; set; } = GetAges(0, 1000, 1_000_000); // Same arbitrary bounds as above
public List<int> GetAges(int minAge, int maxAge, int count)
{
    var ages = new List<int>();
    var rng = new Random();
    for (int i = 0; i < count; i++)
    {
        ages.Add(rng.Next(minAge, maxAge));
    }
    return ages;
}

[Theory]
[/* something with Ages */]
public void AgeFromDateOfBirthFromAge(/* what goes here? */)
{
    var randomDateOfBirth = GenerateDateOfBirth(age); // Where age comes from Ages
    var calculatedAge = GetAge(randomDateOfBirth);
    Assert.Equal(age, calculatedAge);
}

这看起来更简洁易读,而且它仍然做同样的事情。我的目标(在我可以编写实际的单元测试之前)是通过用大量随机数据轰炸这两种方法来嗅出任何可能的边缘情况。一旦其中一种方法似乎运行良好,理想情况下,我可以使用它来修复另一种方法,然后对可能保留的(希望)少数边缘情况进行最终审查。有没有办法做到这一点?

两种方法的当前实现

获取年龄的方法

public int GetAge(DateTime dob)
{
    var now = DateTime.Now;

    // Time difference up to the day
    int deltaDays = now.Day - dob.Day;
    int deltaMonths = now.Month - dob.Month;
    int deltaYears = now.Year - dob.Year;
    int age = (deltaDays + 100 * deltaMonths + 10000 * deltaYears) / 10000;

    // Check if time of day has also been reached
    var timeNotReached = now.TimeOfDay.Ticks < dob.TimeOfDay.Ticks;

    return (deltaDays == 0 && deltaMonths == 0 && timeNotReached) ? age - 1 : age;
}

生成出生日期的方法

public DateTime GenerateDateOfBirth(int age = 18)
{
    var rng = new Random();
    var now = DateTime.Now;

    // Get allowed values for birth date
    var maxMonth = now.Month + 1;
    var maxDay = now.Day + 1;
    var maxHour = now.Hour + 1;
    var maxMinute = now.Minute + 1;
    var maxSecond = now.Second + 1;
    var maxMillisecond = now.Millisecond;

    // Choose random allowed values
    var birthYear = now.Year - age;
    var birthMonth = rng.Next(1, maxMonth);
    var birthDay = birthMonth != now.Month ? rng.Next(1, DateTime.DaysInMonth(birthYear, birthMonth) + 1) : rng.Next(1, maxDay);
    var birthHour = rng.Next(1, maxHour);
    var birthMinute = rng.Next(1, maxMinute);
    var birthSecond = rng.Next(1, maxSecond);
    var birthMillisecond = rng.Next(maxMillisecond);

    var dateOfBirth = new DateTime(
        birthYear,
        birthMonth,
        birthDay,
        birthHour,
        birthMinute,
        birthSecond,
        birthMillisecond
    );
    return dateOfBirth;
}

标签: c#unit-testingtesting.net-corexunit

解决方案


推荐阅读