c# – 来自xunit MemberData函数的静态数据计算两次
作者:互联网
我在计算两次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测试将会成功,因为’数据生成’和测试运行将在一个进程上启动
标签:c,xunit,xunit-net 来源: https://codeday.me/bug/20190522/1152568.html