使用xUnit.net调试以下代码的测试方法Test1
和Test2
并设置断点和CreateValueAndReferenceType()
的末尾,您会看到变量valueType
在两次运行中都是相同的,而变量referenceType
是相同的。前者对我来说是令人惊讶的,也是一个问题(为了完整性,我添加了字符串类型的行)。
public class MyFixture : Fixture
{
public void CreateValueAndReferenceType()
{
var valueType = this.Create<int>();
var referenceTye = this.Create<string>();
}
}
public class TestClass1
{
[Fact]
public void Test1()
{
var myFixture = new MyFixture();
myFixture.CreateValueAndReferenceType();
}
}
public class TestClass2
{
[Fact]
public void Test2()
{
var myFixture = new MyFixture();
myFixture.CreateValueAndReferenceType();
}
}
答案 0 :(得分:2)
我认为,您所看到的是与.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
请注意,除一次测试运行外,所有测试都具有相同的数字。