如何在xUnit Theory测试间共享测试数据?
可行方案汇总
1. 测试类静态构造函数初始化
在测试类中添加静态构造函数,xUnit会在该类的所有测试方法执行前仅调用一次静态构造函数,刚好满足只初始化一次测试数据的需求。
示例代码:
public class ListingApiTests { // 静态构造函数,仅执行一次 static ListingApiTests() { InitializeTestDataInDatabase(); } private static void InitializeTestDataInDatabase() { // 具体的数据初始化逻辑:连接数据库、插入预设的筛选测试数据 using var dbContext = new YourDbContext(); // 加判断避免极端场景下重复初始化 if (!dbContext.ListingItems.Any()) { dbContext.ListingItems.AddRange( new ListingItem { Id = 1, Name = "商品A", Category = "电子产品", Price = 100 }, new ListingItem { Id = 2, Name = "商品B", Category = "服饰", Price = 50 }, new ListingItem { Id = 3, Name = "商品C", Category = "电子产品", Price = 200 } ); dbContext.SaveChanges(); } } [Theory] [InlineData("电子产品", 2)] [InlineData("服饰", 1)] [InlineData("家居", 0)] public async Task GetListing_WithCategoryFilter_ReturnsCorrectCount(string category, int expectedCount) { // 调用API的listing方法,传入筛选参数 var result = await YourApiClient.Listing(new { Category = category }); // 断言结果数量符合预期 Assert.Equal(expectedCount, result.Count()); } }
2. 静态Lazy实现线程安全的单次初始化
如果需要更灵活的初始化时机(比如第一次用到数据时才执行初始化),可以用Lazy<T>实现线程安全的延迟单次初始化:
示例代码:
public class ListingApiTests { private static readonly Lazy<bool> _testDataInitialized = new Lazy<bool>(() => { InitializeTestDataInDatabase(); return true; }); private static void InitializeTestDataInDatabase() { using var dbContext = new YourDbContext(); if (!dbContext.ListingItems.Any()) { dbContext.ListingItems.AddRange(/* 预设测试数据 */); dbContext.SaveChanges(); } } [Theory] [InlineData("电子产品", 2)] [InlineData("服饰", 1)] public async Task GetListing_WithCategoryFilter_ReturnsCorrectCount(string category, int expectedCount) { // 第一次调用时触发初始化,后续直接复用 var _ = _testDataInitialized.Value; // 执行测试逻辑 var result = await YourApiClient.Listing(new { Category = category }); Assert.Equal(expectedCount, result.Count()); } }
Lazy<T>默认线程安全,多线程并行测试场景下也只会执行一次初始化逻辑。
3. 使用xUnit集合特性共享上下文
如果后续有更多相关测试需要复用这组数据,可通过[Collection]特性将测试归为同一集合,共享初始化上下文,无需为单个测试方法单独建类:
首先定义集合标记类:
[CollectionDefinition(nameof(ListingTestCollection))] public class ListingTestCollection : ICollectionFixture<ListingTestFixture> { // 仅作为集合标记,无需实现逻辑 }
然后定义负责初始化数据的Fixture类:
public class ListingTestFixture { public ListingTestFixture() { InitializeTestDataInDatabase(); } private static void InitializeTestDataInDatabase() { using var dbContext = new YourDbContext(); if (!dbContext.ListingItems.Any()) { dbContext.ListingItems.AddRange(/* 预设测试数据 */); dbContext.SaveChanges(); } } }
最后在测试类上标记集合特性:
[Collection(nameof(ListingTestCollection))] public class ListingApiTests { [Theory] [InlineData("电子产品", 2)] [InlineData("服饰", 1)] public async Task GetListing_WithCategoryFilter_ReturnsCorrectCount(string category, int expectedCount) { var result = await YourApiClient.Listing(new { Category = category }); Assert.Equal(expectedCount, result.Count()); } // 新增同集合的测试方法,自动共享已初始化的数据 [Theory] [InlineData(100, 1)] [InlineData(150, 2)] public async Task GetListing_WithPriceFilter_ReturnsCorrectCount(decimal maxPrice, int expectedCount) { var result = await YourApiClient.Listing(new { MaxPrice = maxPrice }); Assert.Equal(expectedCount, result.Count()); } }
内容的提问来源于stack exchange,提问作者Terry
相关产品推荐
相关产品推荐

