Andrew Simpson Andrew Simpson - 11 months ago 70
C# Question

Abstracted Dispose Method not called when using nSubstitute

i have this base (abstract) class:

public abstract class StreamWriterBuilderService : IStreamWriterService
{
private Stream fs;
private StreamWriter stream;

public void WriteLine(
string stringToWrite )
{
if ( stream == null )
{
throw new InvalidOperationException( "Tried to call WriteLine on an uninitialised StreamWriterBuilderService" );
}

stream.WriteLine( stringToWrite );
Flush();
}

public void Flush()
{
if ( stream == null )
{
throw new InvalidOperationException( "Tried to call Flush on an uninitialised StreamWriterBuilderService" );
}

stream.Flush();
}

public void Initialise(
string filePath )
{
Contract.Requires<ArgumentNullException>( filePath != null );

fs = File.Open( filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite );
stream = new StreamWriter( fs );
WriteLine("Initialised");
Initialised = true;
}

public bool Initialised { get; private set; }

#region Dispose Implementation

~StreamWriterBuilderService()
{
Dispose( false );
Debug.WriteLine( false, "This StreamWriterBuilderService object was not disposed of" );
}

private bool _isDisposed;

public virtual void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}

protected virtual void Dispose(
bool disposing )
{
if ( _isDisposed )
return;

if ( disposing && Initialised )
{
stream.Dispose();
fs.Dispose();
stream = null;
fs = null;
}

_isDisposed = true;
}

#endregion Dispose Implementation
}


I am unit testing this with:

protected readonly string TargetFilePath = Path.GetTempFileName();
protected const string Header = "Initialised";

protected override void SetContext()
{
SUT = Substitute.For<StreamWriterBuilderService>();
}


and...

private string fileContents;
private const string TestString = @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!£$%^&*()+~@?><|¬";

protected override void Because()
{
base.Because();
SUT.Initialise( TargetFilePath );
SUT.WriteLine( TestString );
SUT.Flush();
SUT.Dispose();
fileContents = File.ReadAllText( TargetFilePath );
}


The trouble I am having is that this:

SUT.Dispose();


does not actually call my Dispose method in my abstract class because it is declared as a virtual method. If I remove the virtual method then the code is played out. However, I need to keep the virtual method there as I need to override elsewhere in my solution...

Answer Source

You should use:

var SUT = Substitute.ForPartsOf<StreamWriterBuilderService>();

This gives you fine control over the specific things you want to substitute. Thus, by default, your Dispose methods won't be substituted.

Alternatively, my recommendation (for this specific scenario) would be to build your own StreamWriterBuilderServiceForTesting class (that inherits from StreamWriterBuilderService). Because NSubstitute would not be involved, you could define its behaviour however you like.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download