是的,但可能很难.Dispose
实施中通常会发生两件事:
在这种情况下,很难验证代码调用,例如Marshal.Release
.一种可能的解决方案是注入一个可以进行处理的对象,并在测试期间将模拟传递给它.这样的效果:
interface ComObjectReleaser {
public virtual Release (IntPtr obj) {
Marshal.Release(obj);
}
}
class ClassWithComObject : IDisposable {
public ClassWithComObject (ComObjectReleaser releaser) {
m_releaser = releaser;
}
// Create an int object
ComObjectReleaser m_releaser;
int obj = 1;
IntPtr m_pointer = Marshal.GetIUnknownForObject(obj);
public void Dispose() {
m_releaser.Release(m_pointer);
}
}
//Using MOQ - the best mocking framework :)))
class ClassWithComObjectTest {
public DisposeShouldReleaseComObject() {
var releaserMock = new Mock<ComObjectReleaser>();
var target = new ClassWithComObject(releaserMock);
target.Dispose();
releaserMock.Verify(r=>r.Dispose());
}
}
Run Code Online (Sandbox Code Playgroud)
Dispose
调用其他类的方法对此的解决方案可能不像上面那么简单.在大多数情况下,Dispose的实现不是虚拟的,因此嘲笑它很难.
一种方法是将这些其他对象包装在一个可模拟的包装器中,类似于System.Web.Abstractions
命名空间对HttpContext
类的操作 - 即HttpContextBase
使用所有虚拟方法定义类,只需将方法调用委托给真实HttpContext
类.
有关如何执行此类操作的更多想法,请查看System.IO.Abstractions项目.
当然不会伤害。客户代码可能会在处置完您的类的对象后尝试使用它。如果您的类是由其他IDisposable
对象组成的,ObjectDisposedException
则如果该异常处于不再可用的状态,则应始终抛出该异常。
当然,您应该只测试对象的外部状态。在下面的示例中,我将属性设置为Disposed
外部以提供状态。
考虑:
internal class CanBeDisposed : IDisposable
{
private bool disposed;
public bool Disposed
{
get
{
if (!this.disposed)
return this.disposed;
throw new ObjectDisposedException("CanBeDisposed");
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
//// Dispose of managed resources.
}
//// Dispose of unmanaged resources.
this.disposed = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,我将如何进行测试:
CanBeDisposed cbd;
using (cbd = new CanBeDisposed())
{
Debug.Assert(!cbd.Disposed); // Best not be disposed yet.
}
try
{
Debug.Assert(cbd.Disposed); // Expecting an exception.
}
catch (Exception ex)
{
Debug.Assert(ex is ObjectDisposedException); // Better be the right one.
}
Run Code Online (Sandbox Code Playgroud)
如果你的类创建并使用非托管资源,那么你绝对应该确保Dispose按照你的预期工作 - 虽然可以认为它更像是一个集成测试,因为你需要跳转的类型通过.
如果您的类只创建/使用托管资源(即它们实现IDisposable),那么您真正需要确保的是在正确的时间调用这些资源上的Dispose方法 - 如果您使用某种形式的DI,那么您可以注入模拟并断言已调用Dispose.
看看你的处置方法的复杂性 - 如果它们只有几行,可能只有1个条件,那么问问自己,单元测试它们是否真的有好处.
归档时间: |
|
查看次数: |
12348 次 |
最近记录: |