Boris Modylevsky
Boris Modylevsky

Reputation: 3099

Disposing TestCaseSource elements in NUnit test

I am using TestCaseSource with NUnit. The below code generates IEnumerable of TestCaseData that represent an archive entry, which is an input for a test.

        private class GithubRepositoryTestCasesFactory
    {
        private const string GithubRepositoryZip = "https://github.com/QualiSystems/tosca/archive/master.zip";

        public static IEnumerable TestCases
        {
            get
            {
                using (var tempFile = new TempFile(Path.GetTempPath()))
                using (var client = new WebClient())
                {
                    client.DownloadFile(GithubRepositoryZip, tempFile.FilePath);

                    using (var zipToOpen = new FileStream(tempFile.FilePath, FileMode.Open))
                    using (var archive = new ZipArchive(zipToOpen, ZipArchiveMode.Read))
                    {
                        foreach (var archiveEntry in archive.Entries.Where(a =>
                            Path.GetExtension(a.Name).EqualsAny(".yaml", ".yml")))
                        {
                            yield return new TestCaseData(archiveEntry);
                        }
                    }
                }
            }
        }
    }

    [Test, TestCaseSource(typeof (GithubRepositoryTestCasesFactory), "TestCases")]
    public void Validate_Tosca_Files_In_Github_Repository_Of_Quali(ZipArchiveEntry zipArchiveEntry)
    {
        var toscaNetAnalyzer = new ToscaNetAnalyzer();

        toscaNetAnalyzer.Analyze(new StreamReader(zipArchiveEntry.Open()));
    }

The above code fails on the following line:

zipArchiveEntry.Open()

with an exception:

System.ObjectDisposedException "Cannot access a disposed object. Object name: 'ZipArchive'."

Is there any way to control the disposing of objects created for test data case?

Upvotes: 2

Views: 592

Answers (1)

Robert Gowland
Robert Gowland

Reputation: 7947

The problem is that the ZipArchive and its children are being disposed of at the end of the using block.

Try rigging up something like this within your fixture fixture:

// MyDisposable an IDisposable with child elements
private static MyDisposable _parent; 

// This will be run once when the fixture is finished running
[OneTimeTearDown]
public void Teardown()
{
    if (_parent != null)
    {
        _parent.Dispose();
        _parent = null;
    }
}

// This will be run once per test which uses it, prior to running the test
private static IEnumerable<TestCaseData> GetTestCases()
{
    // Create your data without a 'using' statement and store in a static member
    _parent = new MyDisposable(true);
    return _parent.Children.Select(md => new TestCaseData(md));
}

// This method will be run once per test case in the return value of 'GetTestCases'
[TestCaseSource("GetTestCases")]
public void TestSafe(MyDisposable myDisposable)
{
    Assert.IsFalse(myDisposable.HasChildren);
}

The key is to set the static member when creating the test case data, then disposing of it on the fixture tear down.

Upvotes: 1

Related Questions