How to test finalizer code (c #). Afterword: the test still fell

    For quite some time I published a post “How to Test Finalizer Code (c #)” , in which I shared my experience in testing code implemented in the finalizer. Not even a year had passed before the test fell. Details under the cut.

    In short, a test method for finalizer code using AppDomain was described:

            [Test]
            public void TestTemporaryFile_without_Dispose()
            {
                const string DOMAIN_NAME = "testDomain";
                const string FILENAME_KEY = "fileName";
                string testRoot = Directory.GetCurrentDirectory();
                AppDomainSetup info = new AppDomainSetup { ApplicationBase = testRoot };
                AppDomain testDomain = AppDomain.CreateDomain(DOMAIN_NAME, null, info);
                testDomain.DoCallBack(delegate
                {
                    MyTemporaryFile temporaryFile = new MyTemporaryFile();
                    Assert.IsTrue(File.Exists(temporaryFile.FileName));
                    AppDomain.CurrentDomain.SetData(FILENAME_KEY, temporaryFile.FileName);
                });
                string createdTemporaryFileName = (string)testDomain.GetData(FILENAME_KEY);
                Assert.IsTrue(File.Exists(createdTemporaryFileName)); 
                AppDomain.Unload(testDomain);       // выгружается код и очищается вся память (вызывается финализатор), файл удаляется
                Assert.IsFalse(File.Exists(createdTemporaryFileName)); 
            }
    


    As foreboding wrote in the notes:
    3. Most likely the implementation of this test also has all sorts of subtle points, but many years of practice have never recorded a false positive for this test.


    Less than a year after the publication of this post and the test still fell in the line:
    Assert.IsTrue(File.Exists(createdTemporaryFileName)); 
    

    This line verifies that the file created in the domain still exists, although the object is no longer there.

    At first, I didn’t even believe it: I started it again, once again it passed. Then I started the test with the Repeat attribute :
            [Test]
            [Repeat(1000)]
            public void TestTemporaryFile_without_Dispose()
            {
               ...
            }
    

    and the test fell.

    He experimented and got that the test crashes 7-8 times in 1000 starts (0.7% -0.8%) on my computer.

    If I understand correctly, then sometimes (quite rarely) the finalizer of the object is called very quickly and this test simply does not have time to make sure that the file still exists.
    I had to abandon checking the existence of the file: now the test verifies that the file does not exist after unloading the application domain (AppDomain.Unload).

    Now, if I go further, I’ll expect this test to crash on checking for the absence of a file, because this file (a standard temporary file) can be recreated by the operating system from another (parallel) test or, in general, by another program.

    What am I doing wrong?
    I have a problem, the process creates and destroys temporary files, the process can live for a long time, during this time, if it is bad to delete the created temporary files, they just physically run out and the next attempt to get a temporary file from the operating system will fail.

    So, I see such options:
    - check the accidental fall of this test once in a while;
    - Score for tests (check a couple of times with handles);
    - do not use standard temporary files.

    Also popular now: