10

Resolved

Theory Data Disposal facility

description

When I use TheoryAttribute along with a ClassData that emits test parameters that are IDisposable, they don't get Dispose()d in the course of normal test execution.

I've tried doing it in the Dispose path of the underlying Enumerator, but unfortunately, TheoryAttribute.EnumerateTestCommands will cause such a Dispose to take place prior to the execution of any TheoryCommands.

I would like some way to be able to hook in Disposal after each TheoryCommand has been visited - ideally without getting involved in deriving from TheoryCommand and more importantly TheoryAttribute.

I'm not necessarily suggesting that the default behavior should be to Dispose all Theory parameters (though it would work very across all my test suites of various kinds and it 'feels right' to me).

Or is this possible and I'm just missing it?

More info: Underlying requirement is to be able to cause a Quit on each Selenium RemoteWebDriver after each test has been visited. Arguably my overall problem would be best solved by having an 'after batch of tests executed in this Assembly' more generalized
hook.

Failing test that was thwarted:




[Theory]
[ClassData( typeof( XProvider ) )]
public static void ClassDataEnumeratorDisposeShouldHappenAfterTheoryCommandExecution( Disposable d )
{
Assert.False( d.IsDisposed );
}

public class XProvider : SingleItemTheoryDataProvider
{
protected override IEnumerable<object> SingleItemDataSource()
{
    return new SinglePassDisposingWrapper
    {
        new Disposable( "1"),
        new Disposable("2")
    };
}
}

public class SinglePassDisposingWrapper : IEnumerable<object>
{
List<IDisposable> _disposables = new List<IDisposable>();

public void Add( IDisposable disposable )
{
    _disposables.Add( disposable );
}

IEnumerator<object> IEnumerable<object>.GetEnumerator()
{
    if ( _disposables == null )
        throw new ObjectDisposedException( typeof( SinglePassDisposingWrapper ).Name + " may only be enumerated once" );
    foreach ( var item in _disposables )
        yield return item;

    _disposables.ForEach( x => x.Dispose() );
    _disposables = null;
}

IEnumerator IEnumerable.GetEnumerator()
{
    return ((IEnumerable<object>)this).GetEnumerator();
}
}


public class Disposable : IDisposable
{
bool _isDisposed = false;

readonly string _name;

public Disposable( string name )
{
    _name = name;
    Trace.WriteLine( typeof( Disposable ).FullName + ".ctor " + _name );
}

public bool IsDisposed
{
    get { return _isDisposed; }
}

void IDisposable.Dispose()
{
    Trace.WriteLine( typeof( Disposable ).FullName + ".Dispose" + _name );
    _isDisposed = true;
}
}

public abstract class SingleItemTheoryDataProvider : TheoryDataProvider
{
protected override sealed IEnumerable<object[]> DataSource()
{
    return SingleItemDataSource().Select( x => new[] { x } );
}

protected abstract IEnumerable<object> SingleItemDataSource();
}

public abstract class TheoryDataProvider : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
    return DataSource().GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
    return DataSource().GetEnumerator();
}

protected abstract IEnumerable<object[]> DataSource();
}

comments

ajasinski wrote Dec 21, 2012 at 12:31 PM

A possible implementation of a TheoryAttribute-derived class supporting data disposal:
https://gist.github.com/4352462

BradWilson wrote Mar 22, 2014 at 9:37 PM

Resolved in change set 5cabbf3