使用 nSubstitute 时不调用抽象处理方法
Abstracted Dispose Method not called when using nSubstitute
我有这个基础(摘要)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
}
我正在对它进行单元测试:
protected readonly string TargetFilePath = Path.GetTempFileName();
protected const string Header = "Initialised";
protected override void SetContext()
{
SUT = Substitute.For<StreamWriterBuilderService>();
}
和...
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 );
}
我遇到的麻烦是:
SUT.Dispose();
实际上并没有在我的抽象 class 中调用我的 Dispose 方法,因为它被声明为虚拟方法。如果我删除虚拟方法,那么代码就会播放出来。但是,我需要保留虚拟方法,因为我需要在我的解决方案中的其他地方重写...
当您 substitute
像这样 class 时,虚拟 方法将被替换。你可能想要一个部分替代品只替换 Dispose(bool)
.
Documentation about partial substitutes
For starters, NSubstitute can only work with virtual members of the class, so any non-virtual code in the class will actually execute!
也就是说,虚拟方法不会执行。
我会创建一个用于测试目的的派生类型,只是为了删除 abstract
,然后用它进行测试。
你应该使用:
var SUT = Substitute.ForPartsOf<StreamWriterBuilderService>();
这让您 fine control 了解要替换的特定内容。 因此,默认情况下,您的 Dispose
方法不会被替换。
或者,我的建议(针对此特定场景)是构建您自己的 StreamWriterBuilderServiceForTesting
class(继承自 StreamWriterBuilderService
)。 由于不涉及 NSubstitute,您可以根据需要定义其行为。
我有这个基础(摘要)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
}
我正在对它进行单元测试:
protected readonly string TargetFilePath = Path.GetTempFileName();
protected const string Header = "Initialised";
protected override void SetContext()
{
SUT = Substitute.For<StreamWriterBuilderService>();
}
和...
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 );
}
我遇到的麻烦是:
SUT.Dispose();
实际上并没有在我的抽象 class 中调用我的 Dispose 方法,因为它被声明为虚拟方法。如果我删除虚拟方法,那么代码就会播放出来。但是,我需要保留虚拟方法,因为我需要在我的解决方案中的其他地方重写...
当您 substitute
像这样 class 时,虚拟 方法将被替换。你可能想要一个部分替代品只替换 Dispose(bool)
.
Documentation about partial substitutes
For starters, NSubstitute can only work with virtual members of the class, so any non-virtual code in the class will actually execute!
也就是说,虚拟方法不会执行。
我会创建一个用于测试目的的派生类型,只是为了删除 abstract
,然后用它进行测试。
你应该使用:
var SUT = Substitute.ForPartsOf<StreamWriterBuilderService>();
这让您 fine control 了解要替换的特定内容。 因此,默认情况下,您的 Dispose
方法不会被替换。
或者,我的建议(针对此特定场景)是构建您自己的 StreamWriterBuilderServiceForTesting
class(继承自 StreamWriterBuilderService
)。 由于不涉及 NSubstitute,您可以根据需要定义其行为。