这是我拥有的一些代码的简化版本:
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清楚地表明,类固定装置是“在单个类中的测试之间共享对象实例”。
这是一个错误吗?我应该改变使用灯具的方式吗?
我正在将xUnit用于.NET Core 2.3.1。
答案 0 :(得分:2)
否,您已经正确阅读了文档。 TL; DR,因为测试类可以并行运行,所以类夹具必须是独立的,这就是它们的全部重点。
如果xUnit中有一个错误,这会令我感到惊讶,因为此功能/功能稳定且未进行更改。
如果您可以使实际样本失败,那么,是的,这是xUnit中的一个错误,但我是说a)现在没有失败b)您不会使其失败c)SELECT未损坏;)
希望这会有所帮助;)
答案 1 :(得分:2)
正如鲁本·巴特林克(Ruben Bartelink)在答复中说的那样,“选择没有失败”,这意味着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
实例,单例实际上也会使它使用相同的实例。
在我的情况下,我正在独立查看测试类,但我没有意识到有一个单例,因此我认为问题与测试装置有关(错误的假设)。而且由于我在问问题时遗漏了部分内容,因此某人不可能正确地了解出了什么问题。
故事的寓意