我认为,您所看到的是与 .NET 中的伪随机数生成相关的基本问题(IIRC,其他平台也有类似问题)。本质上,System.Random 是确定性的,但使用随机种子进行初始化,除其他外,该种子取决于计算机的当前时间。如果您在紧密循环中创建Random 的实例,则代码的执行速度将超过系统时钟的精度。像这样的:
for (int i = 0; i < 10; i++)
Console.Write(new Random().Next(0, 9));
通常会产生这样的输出:
5555555555
AutoFixture 中的大多数值都是由各种Random 实例生成的——string 类型除外,其中的值由Guid.NewGuid().ToString() 生成。
我认为你看到这个的原因是因为 xUnit.net 的并行执行。
为了查明问题,我重新表述了问题,使其不依赖于调试或继承:
public static class Reporter
{
public static void CreateValueAndReferenceType(
IFixture fixture,
ITestOutputHelper @out)
{
var valueType = fixture.Create<int>();
var referenceTye = fixture.Create<string>();
@out.WriteLine("valueType: {0}", valueType);
@out.WriteLine("referenceType: {0}", referenceTye);
}
}
public class TestClass1
{
private readonly ITestOutputHelper @out;
public TestClass1(ITestOutputHelper @out)
{
this.@out = @out;
}
[Fact]
public void Test1()
{
Reporter.CreateValueAndReferenceType(new Fixture(), this.@out);
}
}
public class TestClass2
{
private readonly ITestOutputHelper @out;
public TestClass2(ITestOutputHelper @out)
{
this.@out = @out;
}
[Fact]
public void Test2()
{
Reporter.CreateValueAndReferenceType(new Fixture(), this.@out);
}
}
当您使用 xUnit.net 控制台运行程序运行此程序时,您可以看到问题很好地重现:
$ packages/xunit.runner.console.2.1.0/tools/xunit.console 37925109/bin/Debug/Ploeh.StackOverflow.Q37925109.dll -diagnostics
-parallel all
xUnit.net Console Runner (64-bit .NET 4.0.30319.42000)
Discovering: Ploeh.StackOverflow.Q37925109 (app domain = on [shadow copy], method display = ClassAndMethod)
Discovered: Ploeh.StackOverflow.Q37925109 (running 2 test cases)
Starting: Ploeh.StackOverflow.Q37925109 (parallel test collections = on, max threads = 4)
Ploeh.StackOverflow.Q37925109.TestClass2.Test2 [PASS]
Output:
valueType: 246
referenceType: cc39f570-046a-4a0a-8adf-ab7deadd0e26
Ploeh.StackOverflow.Q37925109.TestClass1.Test1 [PASS]
Output:
valueType: 246
referenceType: 87455351-03f7-4640-99fb-05af910da267
Finished: Ploeh.StackOverflow.Q37925109
=== TEST EXECUTION SUMMARY ===
Ploeh.StackOverflow.Q37925109 Total: 2, Errors: 0, Failed: 0, Skipped: 0, Time: 0,429s
在上面的示例中,您会注意到我显式使用-parallel all 调用了运行器,但我不必这样做,因为它是默认设置。
另一方面,如果您使用 -parallel none 关闭并行化,您会看到值不同:
$ packages/xunit.runner.console.2.1.0/tools/xunit.console 37925109/bin/Debug/Ploeh.StackOverflow.Q37925109.dll -diagnostics
-parallel none
xUnit.net Console Runner (64-bit .NET 4.0.30319.42000)
Discovering: Ploeh.StackOverflow.Q37925109 (app domain = on [shadow copy], method display = ClassAndMethod)
Discovered: Ploeh.StackOverflow.Q37925109 (running 2 test cases)
Starting: Ploeh.StackOverflow.Q37925109 (parallel test collections = off, max threads = 4)
Ploeh.StackOverflow.Q37925109.TestClass2.Test2 [PASS]
Output:
valueType: 203
referenceType: 1bc75a33-5542-4d9f-b42d-57ed85dc418d
Ploeh.StackOverflow.Q37925109.TestClass1.Test1 [PASS]
Output:
valueType: 117
referenceType: 6a508699-dc35-4bcd-8a7b-15eba64b24b4
Finished: Ploeh.StackOverflow.Q37925109
=== TEST EXECUTION SUMMARY ===
Ploeh.StackOverflow.Q37925109 Total: 2, Errors: 0, Failed: 0, Skipped: 0, Time: 0,348s
我认为由于并行性,Test1 和 Test2 都是并行执行的,并且基本上在同一个时钟周期内。
一种解决方法是将两个测试放在同一个测试类中:
public class TestClass1
{
private readonly ITestOutputHelper @out;
public TestClass1(ITestOutputHelper @out)
{
this.@out = @out;
}
[Fact]
public void Test1()
{
Reporter.CreateValueAndReferenceType(new Fixture(), this.@out);
}
[Fact]
public void Test2()
{
Reporter.CreateValueAndReferenceType(new Fixture(), this.@out);
}
}
这会产生两个不同的整数值,因为 (IIRC) xUnit.net 只能并行运行不同的测试类:
$ packages/xunit.runner.console.2.1.0/tools/xunit.console 37925109/bin/Debug/Ploeh.StackOverflow.Q37925109.dll -diagnostics
-parallel all
xUnit.net Console Runner (64-bit .NET 4.0.30319.42000)
Discovering: Ploeh.StackOverflow.Q37925109 (app domain = on [shadow copy], method display = ClassAndMethod)
Discovered: Ploeh.StackOverflow.Q37925109 (running 2 test cases)
Starting: Ploeh.StackOverflow.Q37925109 (parallel test collections = on, max threads = 4)
Ploeh.StackOverflow.Q37925109.TestClass1.Test2 [PASS]
Output:
valueType: 113
referenceType: e8c30ad8-f2c8-4767-9e9f-69b55c50e659
Ploeh.StackOverflow.Q37925109.TestClass1.Test1 [PASS]
Output:
valueType: 232
referenceType: 3eb60bf3-4d43-4a91-aef2-42f7e23e35b3
Finished: Ploeh.StackOverflow.Q37925109
=== TEST EXECUTION SUMMARY ===
Ploeh.StackOverflow.Q37925109 Total: 2, Errors: 0, Failed: 0, Skipped: 0, Time: 0,360s
如果您将实验重复足够多次,您会不时看到数字不同,这一事实也证实了这一理论。以下是 25 次测试运行的整数结果:
33 33
92 92
211 211
13 13
9 9
160 160
55 55
155 155
137 137
161 161
242 242
183 183
237 237
151 151
104 104
254 254
123 123
244 244
144 144
223 9
196 196
126 126
199 199
221 221
132 132
请注意,除了一个测试运行之外,所有测试运行的数字都相同。