如何确保在应用程序关闭之前处理单例中的对象?
我使用 WatiN 进行一些自动化测试,我发现为每个测试创建 IE 实例是不可扩展的。每个 IE 实例的创建和关闭时间都让我很烦恼:
[TestMethod]
public void Verify_Some_Useful_Thing()
{
using (var browser = new IE())
{
browser.GoTo("/someurl");
// etc..
// some assert() statements
}
}
然而,using 语句确实很有用,因为我始终可以确保我的 IE 实例调用其 dispose() 方法,该方法将关闭 IE 窗口。
无论如何,我创建了一个单例,它维护一个 IE 实例,我的所有测试都在我的所有测试类中使用该实例:
public class BrowserPool
{
private static readonly Lazy<BrowserPool> _instance = new Lazy<BrowserPool>(() => new BrowserPool());
private IE _browser;
private string _ieHwnd;
private int _threadId;
public IE Browser
{
get
{
var currentThreadId = GetCurrentThreadId();
if (currentThreadId != _threadId)
{
_browser = IE.AttachTo<IE>(Find.By("hwnd", _ieHwnd));
_threadId = currentThreadId;
}
return _browser;
}
set
{
_browser = value;
_ieHwnd = _browser.hWnd.ToString();
_threadId = GetCurrentThreadId();
}
}
/// <summary>
/// private to prevent direct instantiation.
/// </summary>
private BrowserPool()
{
Browser = new IE();
}
/// <summary>
/// Get the current executing thread's id.
/// </summary>
/// <returns>Thread Id.</returns>
private int GetCurrentThreadId()
{
return Thread.CurrentThread.GetHashCode();
}
/// <summary>
/// Accessor for instance
/// </summary>
public static BrowserPool Instance
{
get
{
return _instance;
}
}
}
现在的测试:
[TestMethod]
public void Verify_Some_Useful_Thing()
{
var browser = BrowserPool.Instance.Browser;
browser.GoTo("/someurl");
// some assertions
}
这很好用,而且我的测试运行得更快,因为我没有在每个测试中打开和关闭 IE。但是,我遇到了这样一个问题:当测试完成时,我的 IE 实例仍将保持打开状态。
我无法找到一种优雅的方法来确保 BrowserPool.Browser 在应用程序结束之前调用了 dispose() 或 close() 。我什至尝试在 BrowserPool 类中使用终结器,但这似乎不起作用,因为调用终结器时 _browser 变量已经被回收。
如何确保在测试运行后在我的 IE 实例上调用 dispose()?
I'm using WatiN for some automated tests and what I found was that creating an IE instance for every test was not scalable. The creation and shutdown time of each IE instance was eating me alive:
[TestMethod]
public void Verify_Some_Useful_Thing()
{
using (var browser = new IE())
{
browser.GoTo("/someurl");
// etc..
// some assert() statements
}
}
However, the using statement did prove useful in that I can always ensure that my IE instance would have its dispose() method called which would close the IE window.
Anyway, I created a singleton which maintained a single IE instance which all my tests use across all my test classes:
public class BrowserPool
{
private static readonly Lazy<BrowserPool> _instance = new Lazy<BrowserPool>(() => new BrowserPool());
private IE _browser;
private string _ieHwnd;
private int _threadId;
public IE Browser
{
get
{
var currentThreadId = GetCurrentThreadId();
if (currentThreadId != _threadId)
{
_browser = IE.AttachTo<IE>(Find.By("hwnd", _ieHwnd));
_threadId = currentThreadId;
}
return _browser;
}
set
{
_browser = value;
_ieHwnd = _browser.hWnd.ToString();
_threadId = GetCurrentThreadId();
}
}
/// <summary>
/// private to prevent direct instantiation.
/// </summary>
private BrowserPool()
{
Browser = new IE();
}
/// <summary>
/// Get the current executing thread's id.
/// </summary>
/// <returns>Thread Id.</returns>
private int GetCurrentThreadId()
{
return Thread.CurrentThread.GetHashCode();
}
/// <summary>
/// Accessor for instance
/// </summary>
public static BrowserPool Instance
{
get
{
return _instance;
}
}
}
And the test now:
[TestMethod]
public void Verify_Some_Useful_Thing()
{
var browser = BrowserPool.Instance.Browser;
browser.GoTo("/someurl");
// some assertions
}
This works well and my tests run much faster now that I'm not opening and closing IE every test. However, I have this one problem in that when the tests complete my IE instance will still remain open.
I can't figure out an elegant way to ensure that BrowserPool.Browser has dispose() or close() called on it before the application ends. I even tried using a finalizer in the BrowserPool class but that didn't seem to work because the _browser variable had already been reclaimed when my finalizer is called.
How can I ensure that dispose() is called on my IE instance after the test run?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
使用 [ AssemblyCleanupAttribute()] 在程序集中找到的测试完成后清理资源。
顺便说一句,永远不要依赖 .NET 中析构函数的使用。
Use the [AssemblyCleanupAttribute()] to clean resources after your tests found in the assembly are finished.
Btw, never rely on the use of destructors in .NET.