c# – 我在做dotMemory,xUnit和async时做错了什么

我有一个单元测试,我试图验证我已经处理了一个曾经附加到主用户界面的文档.单元测试必须是异步的,因为一切都需要在STA线程下运行,我必须等待创建的用户界面.

我有一个帮助程序将动作调度到STA线程.

我在测试的主体中创建了内存对象,然后将其传递给异步方法,如下所示.

请参阅使用###注释的代码行以查看实际问题行. dotMemory报告该对象尚不存在,但我已经做了一个断言,证明该对象确实存在.

(STA Helper课程可在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下面有两个测试.异步的一个失败,同步一个通过.

[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一样

在完成时,应该收集Async和dotMemoryUnit.TestEnd.

你没有公开STAThread.Run的实现,所以我不能给出更详细的建议,但是想法是在async例程完成时等待测试方法.

点赞