Am I doing something wrong combining dotMemory, xUnit and async

两盒软妹~` 提交于 2019-12-23 12:33:03

问题


I have a unit test where I try to verify that I have disposed of a document that was once attached to the main user interface. The unit test has to be async in that everything needs to be run under an STA thread and I have to await the user interface being created.

I have a helper that dispatches actions onto an STA thread.

I create the memory object in the main body of the test and then pass it to the async methods as below.

See the lines of code commented with ### to see the actual problem line. dotMemory is reporting that the object does not yet exist but I have already made an assertion proving that the object does exist.

( STA Helper classes can be found at https://gist.github.com/bradphelan/cb4f484fbf6a7f9829de0dd52036fd63 )

Is this a problem to do with async and 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);
    }
}

I have created a synchronous version of the same above test and it doesn't fail. There are two tests below ShouldCollectAsync and ShouldCollectSync. The async one fails and the sync one passes.

[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);
    }
}

回答1:


dotMemory Unit requires that all its method should be called from the "test" method. Think about that like there is a call dotMemoryUnit.TestStart at the very begin of ShouldCollectAsync and dotMemoryUnit.TestEnd on finish. You did not expose implementation of STAThread.Run, so I can't give more detailed advise, but the idea is to wait in the test method while you async routine is finished.



来源:https://stackoverflow.com/questions/40968613/am-i-doing-something-wrong-combining-dotmemory-xunit-and-async

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!