gpt4 book ai didi

c# - 来自 xunit MemberData 函数的静态数据被计算两次

转载 作者:太空狗 更新时间:2023-10-29 23:19:57 24 4
gpt4 key购买 nike

我在计算两次 C# Xunit 测试中来自静态类的计算数据时遇到了一些问题。

这将用于的实际生产代码要复杂得多,但后面的代码足以展示我所看到的问题。

在下面的代码中,我有一个随机生成的、延迟加载的 int 种子从当前时间开始。

我在这里测试的只是这个属性等于它自己。我通过 MemberData 函数将属性的值插入到测试中。

由于属性应该只被初始化一次,我希望这个测试应该总是通过。我希望静态字段会在 RandomIntMemberData 函数运行时被初始化,并且再也不会。

但是,这个测试总是失败。插入到测试中的值和测试的值总是不同的。

此外,如果我调试,我只会看到初始化代码被命中一次。即,被测试的值。我从未见过被测试值的初始化。

我是不是误解了什么,或者 Xunit 在幕后做了一些奇怪的魔术来设置它的输入数据,然后在实际运行测试时再次初始化该值?

重现错误的最少代码

public static class TestRandoIntStaticClass
{
private static readonly Lazy<int> LazyRandomInt = new Lazy<int>(() =>
{
// lazily initialize a random interger seeded off of the current time
// according to readings, this should happen only once
return new Random((int) DateTime.Now.Ticks).Next();
});

// according to readings, this should be a thread safe operation
public static int RandomInt => LazyRandomInt.Value;
}

测试

public class TestClass
{
public static IEnumerable<object[]> RandomIntMemberData()
{
var randomInt = new List<object[]>
{
new object[] {TestRandoIntStaticClass.RandomInt},
};

return randomInt as IEnumerable<object[]>;
}

[Theory]
[MemberData(nameof(RandomIntMemberData))]
public void RandoTest(int rando)
{
// these two ought to be equal if TestRandoIntStaticClass.RandomInt is only initialized once
Assert.True(rando == TestRandoIntStaticClass.RandomInt,
$"{nameof(rando)} = {rando} but {nameof(TestRandoIntStaticClass.RandomInt)} = {TestRandoIntStaticClass.RandomInt}");
}
}

最佳答案

在测试发现时,Visual Studio Xunit 控制台运行器创建 AppDomain,其中包含所有属性(如 MemberData、ClassData、DataAttribute)的测试数据,因此所有数据在构建后仅保存在内存中(这也是 XUnit 要求类可序列化的原因).

我们可以通过向您的方法添加一个简单的记录器来验证这一点:

namespace XUnitTestProject1
{
public class TestClass
{
public static IEnumerable<object[]> RandomIntMemberData()
{
var randomInt = new List<object[]>
{
new object[]
{TestRandoIntStaticClass.RandomInt},
};
return randomInt;
}

[Theory]
[MemberData(nameof(RandomIntMemberData))]
public void RandoTest(int rando)
{
// these two ought to be equal if TestRandoIntStaticClass.RandomInt is only initialized once
Assert.True(rando == TestRandoIntStaticClass.RandomInt, $"{nameof(rando)} = {rando} but {nameof(TestRandoIntStaticClass.RandomInt)} = {TestRandoIntStaticClass.RandomInt}");
}

}

public static class TestRandoIntStaticClass
{
private static readonly Lazy<int> LazyRandomInt = new Lazy<int>(() =>
{ // lazily initialize a random interger seeded off of the current time
// according to readings, this should happen only once
var randomValue = new Random((int) DateTime.Now.Ticks).Next();

File.AppendAllText(@"D:\var\log.txt", $"Call TestRandoIntStaticClass {randomValue}; ThreadId {Thread.CurrentThread.ManagedThreadId} " + Environment.NewLine);
return randomValue;
});

public static int RandomInt => LazyRandomInt.Value; // according to readings, this should be a thread safe operation
}
}

结果我们在日志中看到:

> Call TestRandoIntStaticClass 1846311153; ThreadId 11  
> Call TestRandoIntStaticClass 1007825738; ThreadId 14

并在测试执行结果中

rando = 1846311153 but RandomInt = 1007825738
Expected: True
Actual: False
at

但是,如果您使用 dotnet test 将会成功,因为“数据生成”和测试运行将在一个进程上启动

关于c# - 来自 xunit MemberData 函数的静态数据被计算两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53071355/

24 4 0