我在结合 dotMemory、xUnit 和 async 时做错了什么吗
Am I doing something wrong combining dotMemory, xUnit and async
我有一个单元测试,我试图验证我已经处理了曾经附加到主用户界面的文档。单元测试必须是异步的,因为一切都需要 运行 在 STA 线程下,我必须等待正在创建的用户界面。
我有一个助手可以将操作分派到 STA 线程。
我在测试主体中创建了 memory 对象,然后将其传递给异步方法,如下所示。
查看用 ### 注释的代码行以查看实际问题行。 dotMemory 报告该对象尚不存在,但我已经断言证明该对象确实存在。
(STA 助手 类 可以在 https://gist.github.com/bradphelan/cb4f484fbf6a7f9829de0dd52036fd63 找到)
这是与 async 和 dotMemory 相关的问题吗?
[Collection("Memory leaks")]
public class MemLeakSpec
{
public MemLeakSpec(ITestOutputHelper output)
{
DotMemoryUnitTestOutput.SetOutputMethod(output.WriteLine);
}
[Fact]
[DotMemoryUnit(FailIfRunWithoutSupport = true)]
public void ShouldCollectProjectX()
{
dotMemory.Check (memory => { STAThread.Run(() => ShouldCollectProjectAsyncX(memory)).Wait(); });
}
class Document { }
class Container { public Document Document; };
Document CreateFoo() => new Document();
private async Task ShouldCollectProjectAsyncX(Memory memory)
{
await Task.Delay(TimeSpan.FromMilliseconds(50));
Container container = new Container();
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
Document documentA = CreateFoo();
container.Document = documentA;
// Verify with dotMemory that the object exists.
// ### This fails even though I have verified
// ### the document exists
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(1);
// Open a new project which should dispose the old one and thus
// remove any reference to GenericWeinCadFolder
container.Document = null;
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
GC.KeepAlive(container);
}
}
我已经创建了上述相同测试的同步版本并且没有失败。下面有两个测试 ShouldCollectAsync 和 ShouldCollectSync。 async 失败,sync 通过。
[Collection("Memory leaks")]
public class MemLeakSpec
{
public MemLeakSpec(ITestOutputHelper output)
{
DotMemoryUnitTestOutput.SetOutputMethod(output.WriteLine);
}
[Fact]
[DotMemoryUnit(FailIfRunWithoutSupport = true)]
public void ShouldCollectAsync()
{
dotMemory.Check (memory => { STAThread.Run(() => ShouldCollectProjectAsyncX(memory)).Wait(); });
}
/// This test is almost identical to the ShouldCollectAsync
/// but it passes
[Fact]
[DotMemoryUnit(FailIfRunWithoutSupport = true)]
public void ShouldCollectSync ()
{
dotMemory.Check (memory => { STAThread.Run(() => ShouldCollectProjectSync(memory)); });
}
class Document { }
class Container { public Document Document; };
Document CreateFoo() => new Document();
private async Task ShouldCollectProjectSync(Memory memory)
{
Container container = new Container();
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
Document documentA = CreateFoo();
container.Document = documentA;
// Verify with dotMemory that the object exists.
// #### Passes here
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(1);
GC.KeepAlive(documentA);
GC.KeepAlive(container);
}
private async Task ShouldCollectProjectAsyncX(Memory memory)
{
await Task.Delay(TimeSpan.FromMilliseconds(50));
Container container = new Container();
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
Document documentA = CreateFoo();
container.Document = documentA;
// Verify with dotMemory that the object exists.
// #### FAILS here
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(1);
GC.KeepAlive(documentA);
GC.KeepAlive(container);
}
}
dotMemory Unit 要求其所有方法都应从 "test" 方法调用。
想一想就像在开始时有一个电话 dotMemoryUnit.TestStart
ShouldCollectAsync 和 dotMemoryUnit.TestEnd 完成。
您没有公开 STAThread.Run 的实现,所以我无法提供更详细的建议,但想法是在异步例程完成时在测试方法中等待。
对我来说,将测试包装在本地函数中就足够了:
public void TestMethod()
{
async Task LocalFunction()
{
// here you can make async calls
await Task.Delay(...);
}
LocalFunction().ConfigureAwait(true).GetAwaiter().GetResult();
}
我有一个单元测试,我试图验证我已经处理了曾经附加到主用户界面的文档。单元测试必须是异步的,因为一切都需要 运行 在 STA 线程下,我必须等待正在创建的用户界面。
我有一个助手可以将操作分派到 STA 线程。
我在测试主体中创建了 memory 对象,然后将其传递给异步方法,如下所示。
查看用 ### 注释的代码行以查看实际问题行。 dotMemory 报告该对象尚不存在,但我已经断言证明该对象确实存在。
(STA 助手 类 可以在 https://gist.github.com/bradphelan/cb4f484fbf6a7f9829de0dd52036fd63 找到)
这是与 async 和 dotMemory 相关的问题吗?
[Collection("Memory leaks")]
public class MemLeakSpec
{
public MemLeakSpec(ITestOutputHelper output)
{
DotMemoryUnitTestOutput.SetOutputMethod(output.WriteLine);
}
[Fact]
[DotMemoryUnit(FailIfRunWithoutSupport = true)]
public void ShouldCollectProjectX()
{
dotMemory.Check (memory => { STAThread.Run(() => ShouldCollectProjectAsyncX(memory)).Wait(); });
}
class Document { }
class Container { public Document Document; };
Document CreateFoo() => new Document();
private async Task ShouldCollectProjectAsyncX(Memory memory)
{
await Task.Delay(TimeSpan.FromMilliseconds(50));
Container container = new Container();
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
Document documentA = CreateFoo();
container.Document = documentA;
// Verify with dotMemory that the object exists.
// ### This fails even though I have verified
// ### the document exists
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(1);
// Open a new project which should dispose the old one and thus
// remove any reference to GenericWeinCadFolder
container.Document = null;
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
GC.KeepAlive(container);
}
}
我已经创建了上述相同测试的同步版本并且没有失败。下面有两个测试 ShouldCollectAsync 和 ShouldCollectSync。 async 失败,sync 通过。
[Collection("Memory leaks")]
public class MemLeakSpec
{
public MemLeakSpec(ITestOutputHelper output)
{
DotMemoryUnitTestOutput.SetOutputMethod(output.WriteLine);
}
[Fact]
[DotMemoryUnit(FailIfRunWithoutSupport = true)]
public void ShouldCollectAsync()
{
dotMemory.Check (memory => { STAThread.Run(() => ShouldCollectProjectAsyncX(memory)).Wait(); });
}
/// This test is almost identical to the ShouldCollectAsync
/// but it passes
[Fact]
[DotMemoryUnit(FailIfRunWithoutSupport = true)]
public void ShouldCollectSync ()
{
dotMemory.Check (memory => { STAThread.Run(() => ShouldCollectProjectSync(memory)); });
}
class Document { }
class Container { public Document Document; };
Document CreateFoo() => new Document();
private async Task ShouldCollectProjectSync(Memory memory)
{
Container container = new Container();
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
Document documentA = CreateFoo();
container.Document = documentA;
// Verify with dotMemory that the object exists.
// #### Passes here
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(1);
GC.KeepAlive(documentA);
GC.KeepAlive(container);
}
private async Task ShouldCollectProjectAsyncX(Memory memory)
{
await Task.Delay(TimeSpan.FromMilliseconds(50));
Container container = new Container();
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(0);
Document documentA = CreateFoo();
container.Document = documentA;
// Verify with dotMemory that the object exists.
// #### FAILS here
memory.GetObjects(@where => @where.Type.Is<Document>())
.ObjectsCount.Should()
.Be(1);
GC.KeepAlive(documentA);
GC.KeepAlive(container);
}
}
dotMemory Unit 要求其所有方法都应从 "test" 方法调用。 想一想就像在开始时有一个电话 dotMemoryUnit.TestStart ShouldCollectAsync 和 dotMemoryUnit.TestEnd 完成。 您没有公开 STAThread.Run 的实现,所以我无法提供更详细的建议,但想法是在异步例程完成时在测试方法中等待。
对我来说,将测试包装在本地函数中就足够了:
public void TestMethod()
{
async Task LocalFunction()
{
// here you can make async calls
await Task.Delay(...);
}
LocalFunction().ConfigureAwait(true).GetAwaiter().GetResult();
}