如何添加更多测试数据来断言哪个 returns 对象?

How do I add more test data to assert which returns object?

我在 Xunit 中进行了这个集成测试。

[Fact]
public async Task AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass()
{
    var campaign = new Campaign
    {
        Title = "Test",
        StartDate = new DateTime(2021, 6, 5),
        EndDate = new DateTime(2021, 6, 6)
    };

    using (var context = new CampaignDbContext(_options))
    {
        _campaignService = new CampaignService(context);

        var actualCampaign = await _campaignService.AddCampaignAsync(campaign);

        Assert.Equal(campaign.Title, actualCampaign.Title);
        Assert.Equal(campaign.StartDate, actualCampaign.StartDate);
        Assert.Equal(campaign.EndDate, actualCampaign.EndDate);
    }
}

AddCampaignAsync 的代码如下:

    public async Task<Campaign> AddCampaignAsync(Campaign campaign)
    {            
        if (campaign.EndDate != null) {
            if (campaign.StartDate > campaign.EndDate)
            {
                throw new Exception("The campaign start date cannot be greater than end date");
            }
        }
        
        await _context.Campaigns.AddAsync(campaign);
        await _context.SaveChangesAsync();
        return campaign;
    }

它工作正常。但是我可以传入 campaigncollection 作为测试数据,而不是只将一个 campaign 对象作为测试数据吗?

您可以使用数据驱动测试。

例如:

[Theory]
[InlineData("Test1", "2021-06-05", "2021-06-06")]
[InlineData("Test2", "2021-06-07", "2021-06-08")]
public async Task AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass(string title, DateTime startDate, DateTime endDate)
{
    var campaign = new Campaign
    {
        Title = title,
        StartDate = startDate,
        EndDate = endDate
    };
    ...

您可以在此处找到更多示例:https://andrewlock.net/creating-parameterised-tests-in-xunit-with-inlinedata-classdata-and-memberdata/

首先,从测试方法中删除campaign,并将其作为方法的参数。然后删除 Fact 属性并添加 Theory 属性。 Fact 属性通常用于测试不涉及数据集合的地方。需要对不同数据多次 运行 的测试通常用 Theory:

修饰
[Theory]
public async Task AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass(Campaign campaign)
{

    using (var context = new CampaignDbContext(_options))
    {
        _campaignService = new CampaignService(context);

        var actualCampaign = await _campaignService.AddCampaignAsync(campaign);

        Assert.Equal(campaign.Title, actualCampaign.Title);
        Assert.Equal(campaign.StartDate, actualCampaign.StartDate);
        Assert.Equal(campaign.EndDate, actualCampaign.EndDate);
    }
}

有几个选项可以为测试方法提供测试数据。

1。继承自 TheoryData<T>

TheoryData用于为测试方法的参数提供数据。它为不同的方法参数长度定义了几个通用重载。 AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass 有一个参数 Campaign,所以继承自 TheoryData<Campaign>:

public class CampaignData : TheoryData<Campaign>
{
    public CampaignData()
    {
        Add(new Campaign { Title = "Test1", StartDate = new DateTime(2021, 1, 5), EndDate = new DateTime(2021, 10, 6) });
        Add(new Campaign { Title = "Test2", StartDate = new DateTime(2021, 2, 5), EndDate = new DateTime(2021, 9, 6) });
        Add(new Campaign { Title = "Test3", StartDate = new DateTime(2021, 3, 5), EndDate = new DateTime(2021, 8, 6) });
        Add(new Campaign { Title = "Test4", StartDate = new DateTime(2021, 4, 5), EndDate = new DateTime(2021, 7, 6) });
    }
}

在构造函数中,调用Add方法将Campaign个对象添加到集合中。现在你可以做的是使用 ClassData 属性:

[Theory]
[ClassData(typeof(CampaignData))]
public async Task AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass(Campaign campaign)
{

    using (var context = new CampaignDbContext(_options))
    {
        _campaignService = new CampaignService(context);

        var actualCampaign = await _campaignService.AddCampaignAsync(campaign);

        Assert.Equal(campaign.Title, actualCampaign.Title);
        Assert.Equal(campaign.StartDate, actualCampaign.StartDate);
        Assert.Equal(campaign.EndDate, actualCampaign.EndDate);
    }
}

使用 ClassData(typeof(CampaignData)),您告诉 xUnit CampaignData class 具有调用此方法所需的所有参数。

2。使用 MemberData

如果您不想创建新的 class,您也可以将集合项定义为同一 class 的静态成员。在同一个 class 中,您有 AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass 方法,定义一个静态 属性 或像这样的字段。 属性 的类型是 IEnumerable<object[]>。它是 object[] 个数组的集合。集合中的每个 object 数组都为测试方法定义了一个参数列表,您的测试方法有一个参数 Campaign campaign。所以每个对象数组可以包含一个 Campaign 对象。然后在 AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass 添加 MemberData 属性,名称为 属性:

class YourTestClass
{
    public static IEnumerable<object[]> Campaigns => new List<object[]>
    {
        new object[]
        {
            new Campaign { Title = "Test1", StartDate = new DateTime(2021, 1, 5), EndDate = new DateTime(2021, 10, 6) },
            new Campaign { Title = "Test2", StartDate = new DateTime(2021, 2, 5), EndDate = new DateTime(2021, 9, 6) },
            new Campaign { Title = "Test3", StartDate = new DateTime(2021, 3, 5), EndDate = new DateTime(2021, 8, 6) },
            new Campaign { Title = "Test4", StartDate = new DateTime(2021, 4, 5), EndDate = new DateTime(2021, 7, 6) }
        }
    };


    [Theory]
    [MemberData(nameof(Campaigns))]
    public async Task AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass(Campaign campaign)
    {

        using (var context = new CampaignDbContext(_options))
        {
            _campaignService = new CampaignService(context);

            var actualCampaign = await _campaignService.AddCampaignAsync(campaign);

            Assert.Equal(campaign.Title, actualCampaign.Title);
            Assert.Equal(campaign.StartDate, actualCampaign.StartDate);
            Assert.Equal(campaign.EndDate, actualCampaign.EndDate);
        }
    }
}

这将使用 Campaigns 属性.

object 数组中的每个 Campaign 对象调用方法 AddCampaignAsync_GivenUniqueTitle_GivenGoodDates_ShouldPass

如果您只有几个 Campaign 对象要测试,Sergei 使用 InlineData 属性的方法是一个不错的选择。

参考:https://andrewlock.net/creating-strongly-typed-xunit-theory-test-data-with-theorydata/(你可以在这里找到更多的方法)