【问题标题】:Does XUnit share fixture instances across test classes?XUnit 是否跨测试类共享夹具实例?
【发布时间】:2019-05-21 01:17:39
【问题描述】:

这是我的一些代码的简化版本:

public class FixtureData
{
    public object SomeValue { get; set; }
}

public class TestForNull : IClassFixture<FixtureData>
{
    private readonly FixtureData _data;

    public TestForNull(FixtureData data)
    {
        _data = data;
    }

    [Fact]
    public void TestForNull()
    {
        _data.SomeValue = null;
        Assert.Null(_data.SomeValue);
    }
}

public class TestForObject : IClassFixture<FixtureData>
{
    private readonly FixtureData _data;

    public TestForObject(FixtureData data)
    {
        _data = data;
    }

    [Fact]
    public void TestForObject()
    {
        Assert.NotNull(_data.SomeValue);
    }
}

这两个类都没有标记任何集合属性。它们都属于同一个程序集。

我看到这些测试失败(但只是偶尔失败),这只能通过 XUnit 在测试类之间共享 FixtureData 实例和 TestForNull 先运行(因为它有副作用)来解释。

不过,XUnit documentation 清楚地表明,类固定装置是“在单个类中的测试之间共享对象实例”。

这是一个错误吗?我应该改变我使用灯具的方式吗?

我正在为 .NET Core 2.3.1 使用 xUnit。

【问题讨论】:

    标签: unit-testing xunit fixtures xunit.net


    【解决方案1】:

    不,您已正确阅读文档。 TL;DR 因为测试类可以并行运行,所以类夹具必须是独立的,这就是它们的全部意义所在。

    如果 xUnit 中存在错误,我会感到惊讶,因为此功能/设施是稳定的并且不会发生变化。

    如果你可以让你的实际样本失败,那么,是的,这是 xUnit 中的一个错误,但我是说 a) 它现在没有失败 b) 你不会让它失败 c) SELECT 没有损坏;)

    希望这会有所帮助;)

    【讨论】:

    • 绝对是对的。 (不是讽刺。)我发现有更多相关的上下文并为我创造了这个问题。我将提供一个答案,详细说明这是如何发生的。谢谢!
    【解决方案2】:

    正如 Ruben Bartelink 在他的回复中所说,“SELECT 没有被破坏”,这意味着这是 XUnit 的一个非常核心的功能,一个经过充分验证的测试框架,问题不太可能在他们这边。

    此外,深入研究 XUnit 代码,这就是它生成类固定装置的作用:(Source)

    var createClassFixtureAsyncTasks = new List<Task>();
    foreach (var interfaceType in testClassTypeInfo.ImplementedInterfaces.Where(i => i.GetTypeInfo().IsGenericType && i.GetGenericTypeDefinition() == typeof(IClassFixture<>)))
        createClassFixtureAsyncTasks.Add(CreateClassFixtureAsync(interfaceType.GetTypeInfo().GenericTypeArguments.Single()));
    
    if (TestClass.TestCollection.CollectionDefinition != null)
    {
        var declarationType = ((IReflectionTypeInfo)TestClass.TestCollection.CollectionDefinition).Type;
        foreach (var interfaceType in declarationType.GetTypeInfo().ImplementedInterfaces.Where(i => i.GetTypeInfo().IsGenericType && i.GetGenericTypeDefinition() == typeof(IClassFixture<>)))
            createClassFixtureAsyncTasks.Add(CreateClassFixtureAsync(interfaceType.GetTypeInfo().GenericTypeArguments.Single()));
    }
    
    await Task.WhenAll(createClassFixtureAsyncTasks);
    

    从对CreateClassFixtureAsync 的调用中,很容易看出类固定装置每次都为测试用例重新生成

    那我观察到的行为是为什么?

    我不小心在我的示例中简化了我应该有的更多内容。我发现这可能是正在发生的事情的一个更好的例子:

    public class FixtureData
    {
        public object SomeValue => HiddenSingleton.Instance.SomeValue;
    }
    
    public class HiddenSingleton
    {
        private static HiddenSingleton _instance;
        public static HiddenSingleton Instance
        {
            get
            {
                if (_instance != null) return _instance;
    
                _instance = new HiddenSingleton();
                return _instance;
            }
        }
    
        public object SomeValue { get; set; }
    }
    
    public class TestForNull : IClassFixture<FixtureData>
    {
        private readonly FixtureData _data;
    
        public TestForNull(FixtureData data)
        {
            _data = data;
        }
    
        [Fact]
        public void TestForNull()
        {
            _data.SomeValue = null;
            Assert.Null(_data.SomeValue);
        }
    }
    
    public class TestForObject : IClassFixture<FixtureData>
    {
        private readonly FixtureData _data;
    
        public TestForObject(FixtureData data)
        {
            _data = data;
        }
    
        [Fact]
        public void TestForObject()
        {
            Assert.NotNull(_data.SomeValue);
        }
    }
    

    在这种情况下,直接看,很明显:尽管 XUnit 为每个测试生成了一个独立的 FixtureData 实例,但单例实际上使它们使用相同的实例。

    在我的例子中,我正在独立查看测试类,但我没有意识到有一个单例,所以我认为问题与测试装置有关(假设不正确)。而且由于我在提问时遗漏了部分内容,因此有人不可能正确地找出问题所在。

    故事的寓意:

    • 信任测试框架(特别是如果他们专门从事测试!)
    • Stop overusing singletons
    • 在 StackOverflow 中提问之前,请确保您已了解问题的所有相关部分

    【讨论】:

    • 我喜欢这样的跟进,太好了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多